搭建MySQL集群

本文MySQL集群采用一主多从的架构,即一个master节点多个slave节点,master负责写数据,slave节点负责读操作。使用mycat作为MySQL中间件向外提供读写服务。使用phpmyadmin提供外部服务,整体架构如下:


架构

1 搭建MySQL集群

这里采用1主2从的结构,一般在一主多从的结构中,slave节点在2-4个之间,如果slave节点多了,会影响master的性能。操作步骤如下:

  • 创建3个MySQL容器
  • 配置Master节点
  • 配置Slave节点

1.1 创建MySQL容器

本文采用docker-compose创建MySQL容器,使用docker-compose需要创建docker-compose.yml.env 2个文件,其中 docker-compose.yml是配置文件文件,是必需的。.env 是docker-compose的环境变量文件,是可选的。配置文件可以读取环境变量文件中定义的变量,方便扩展。

创建一个docker目录,并在docker目录下创建mysql目录,~/docker/mysql作为本项目的根目录。在mysql根目录下,创建master,slave1和slave2目录,用于存放3个mysql实例。并在根目录下,创建docker-compose的配置文件和环境变量文件。

mkdir -p ~/docker/mysql/master ~/docker/mysql/slave1 ~/docker/mysql/slave2
cd ~/docker/mysql
touch .env docker-compose.yml

目录结构如下:

➜  mysql tree -L 1 -a
.
├── .env    #docker-compose环境变量
├── docker-compose.yml #docker-compose配置文件
├── master  # 存储master实例
├── slave1  # 存储slave1实例
└── slave2  # 存储slave2实例

3 directories, 2 files

设置环境变量

➜  mysql vim .env

# 使用的MySQL版本
MYSQL_VERSION=mysql:5.7.30
# MySQL root用户密码
MYSQL_ROOT_PASSWORD=123456
# MySQL 实例存储的根目录
MYSQL_HOME=/Users/zebra/docker/mysql

# master配置
MASTER=master
MASTER_PORT=33061

# salve1配置
SLAVE1=slave1
SLAVE1_PORT=33062

# slave2配置
SLAVE2=slave2
SLAVE2_PORT=33063

设置配置文件docker-compose.yml

version: '3'

services: 
    master: 
        restart: always 
        image: ${MYSQL_VERSION}
        container_name: ${MASTER}
        environment: 
            # root密码
            MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
            # 使用环境变量设置MySQL的时区
            TZ: Asia/Shanghai
        ports:
            - ${MASTER_PORT}:3306
        volumes:
            - ${MYSQL_HOME}/master/data:/var/lib/mysql
            - ${MYSQL_HOME}/master/etc/conf.d:/etc/mysql/conf.d
        command: 
            # 设置忽略大小写
            - --lower_case_table_names=1
            # 设置默认字符集
            - --character-set-server=utf8mb4
            - --collation-server=utf8mb4_general_ci
            # 设置最大接收的数据包
            - --max_allowed_packet=128M
    slave1: 
        restart: always 
        image: ${MYSQL_VERSION}
        container_name: ${SLAVE1}
        environment: 
            # root密码
            MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
            # 使用环境变量设置MySQL的时区
            TZ: Asia/Shanghai
        links: 
            - ${MASTER}
        ports:
            - ${SLAVE1_PORT}:3306
        volumes:
            - ${MYSQL_HOME}/slave1/data:/var/lib/mysql
            - ${MYSQL_HOME}/slave1/etc/conf.d:/etc/mysql/conf.d
        command: 
            # 设置忽略大小写
            - --lower_case_table_names=1
            # 设置默认字符集
            - --character-set-server=utf8mb4
            - --collation-server=utf8mb4_general_ci
            # 设置最大接收的数据包
            - --max_allowed_packet=128M
    slave2: 
        restart: always 
        image: ${MYSQL_VERSION}
        container_name: ${SLAVE2}
        environment: 
            # root密码
            MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
            # 使用环境变量设置MySQL的时区
            TZ: Asia/Shanghai
        links: 
            - ${MASTER}
        ports:
            - ${SLAVE2_PORT}:3306
        volumes:
            - ${MYSQL_HOME}/slave2/data:/var/lib/mysql
            - ${MYSQL_HOME}/slave2/etc/conf.d:/etc/mysql/conf.d
        command: 
            # 设置忽略大小写
            - --lower_case_table_names=1
            # 设置默认字符集
            - --character-set-server=utf8mb4
            - --collation-server=utf8mb4_general_ci
            # 设置最大接收的数据包
            - --max_allowed_packet=128M

docker-compose.yml文件中,定义了3个MySQL容器,其中2个slave容器使用links关联了master容器,这样可以在后续的操作中使用master主机名代替其ip地址。

在上面的配置文件,我们使用volumes选项将容器中的目录挂载到本地。每个节点都有2个目录,分别是:

  • data目录,映射容器中/var/lib/mysql目录,用于存储MySQL实例
  • etc/conf.d 目录,映射容器中/etc/mysql/conf.d目录,用于存储MySQL的配置文件

1.2 设置MySQL配置文件

既然知道了MySQL的配置文件存放的地方,那么我们就可以设置MySQL的配置,让其开启主从模块。首先设置master的配置文件,在master目录下创建etc/conf.d目录。

# 创建conf.d目录
mkdir -p master/etc/conf.d

# 编辑my.cnf配置文件
vim master/etc/conf.d/my.cnf

#my.cnf 内容

[mysqld]
# 主服务器唯一ID
server-id=1
# 启用binlog日志
log-bin=mysql-bin
# 要复制的数据库,这里的数据库名为testdb,如果有多个库,可以设置多个binlog-do-db项
binlog-do-db=testdb
# 不需要复制的数据库
binlog-ignore-db=mysql
binlog-ignore-db=information_schema

在master的配置文件中,我们设置的要复制的数据库名为testdb,其他需要注意的是,在MySQL集群中server-id不能重复,这里我们将master的server-id设置为1(后面的slave1设置为2,slave2设置为3)。

slave1的my.cnf文件在slave1/etc/conf.d目录中(需要自己创建),配置如下:

[mysqld]
# 主服务器唯一ID
server-id=2

同理,slave2节点的my.cnf如下:

[mysqld]
# 主服务器唯一ID
server-id=3

1.3 运行MySQL容器

通过上面的配置,我们就可以通过docker-compose 启动MySQL容器了,不过,在启动之前,我们先来看看目录的结构:

➜  mysql tree -a .
.
├── .env                                    # docker-compose 环境变量文件
├── docker-compose.yml      # docker-compose 配置文件
├── master
│   └── etc
│       └── conf.d
│           └── my.cnf      # mysql配置文件
├── slave1
│   └── etc
│       └── conf.d
│           └── my.cnf      # mysql配置文件
└── slave2
    └── etc
        └── conf.d
            └── my.cnf      # mysql配置文件

9 directories, 5 files

在mysql根目录中执行如下语句,docker-compose会在当前目录中读取.evndocker-compose.yml文件来启动docker容器。

➜  mysql docker-compose up -d
Creating network "mysql_default" with the default driver
Creating master ... done
Creating slave1 ... done
Creating slave2 ... done

docker-compose up 命令是启动容器,-d选项表示后台运行容器,如果要关闭容器使用docker-compose down命令。使用tree命令查看目录结构

➜  mysql tree -adL 2 .
.
├── master
│   ├── data        # 数据库挂载点
│   └── etc
├── slave1
│   ├── data        # 数据库挂载点
│   └── etc
└── slave2
    ├── data        # 数据库挂载点
    └── etc

9 directories

可以看到目录中多了一个data目录,该目录是我们在配置文件中通过volumes选项映射出来的容器卷,它将容器中的数据库文件保存在本地目录,避免容器销毁后,数据也跟着销毁。

1.4 初始化MySQL集群

现在,容器已经启动了。之前我们在my.cnf配置中做了一部分集群的设置,但仅仅设置集群中的每个节点id,并开启了master主机的binary log日志。我们还需要解决的是:

  • master节点允许什么用户复制哪些数据库
  • slave节点通过什么用户到哪里去复制数据库

登录master节点,使用grant语句,将所有数据库的所有对象的replication slave 权限,授权给slave用户,并且slave用户可以使用网络地址访问,其密码是123456

mysql> grant replication slave on *.* to 'slave'@'%' identified by '123456';
Query OK, 0 rows affected (0.01 sec)

查看master状态:

mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB         | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000003 |      430 | testdb       | mysql,information_schema |                   |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)

记住文件FilePosition参数的值,File参数是binlog日志的文件,也是slave要拷贝的文件。position代表要slave拷贝的起点,如果在maste上执行SQL语句,Position的值会发生变化,所以确定了position后,先暂时不要操作master。

登录slave节点,使用如下语句配置slave节点的连接信息,包括登录master的用户名、密码、端口信息,以及刚刚在master上查询的file和position参数。

change master to master_host='master',
 master_user='slave', 
 master_password='123456',
 master_port=3306,
 master_log_file='mysql-bin.000003',
 master_log_pos= 430,
 master_connect_retry=30;

因为在docker-compose.yml中使用了link,所以这里的master_host 参数使用的是master的主机名。查看slave状态:

mysql> show slave status \G;
*************************** 1. row ***************************
         Slave_IO_State: 
            Master_Host: master
            Master_User: slave
            Master_Port: 3306
          Connect_Retry: 30
        Master_Log_File: mysql-bin.000003
    Read_Master_Log_Pos: 430
         Relay_Log_File: 9e185c56ef5e-relay-bin.000001
          Relay_Log_Pos: 4
  Relay_Master_Log_File: mysql-bin.000003
       Slave_IO_Running: No
      Slave_SQL_Running: No
  ...

我们仅仅是设置了连接信息,还没有启动slave,所以可以看到Slave_IO_RunningSlave_SQL_Running两个线程都是No状态。执行start slave语句:

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

启动slave后,Slave_IO_RunningSlave_SQL_Running两个线程都是Yes状态。

到此,MySQL集群已搭建完成。Master创建testdb库后,slave会同步该库。

2 搭建MyCAT中间件

Mycat是使用Java语言进行编写开发,使用前需要先安装Java运行环境(JRE),由于Mycat中使用了jdk7中的一些特性,所以要求必须在JDK7以上的版本上运行。

使用Mycat可以:

  • 数据库分片(垂直和水平)
  • 读写分离

本文只涉及到读写分离特性,更多的内容可参考MyCAT官网

2.1 目录准备

在mysql目下创建一个mycat目录,作为mycat节点的根目录,用于存放Mycat配置和日志等数据。我们使用DockerFile文件生成Mycat镜像,所以需要创建Dockerfile文件。同时,到Mycat官网下载Mycat安装包(这里重命名为Mycat.tar.gz),地址如下:

http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz

目录结构如下:

➜  mycat tree -L 1 
.
├── Dockerfile          # dockerfile 文件
└── mycat.tar.gz    # mycat 安装包

因为后面启动mycat容器时,我们需要将mycat的配置文件目录conf作为数据卷挂载到容器中,所以这里需要先将mycat安装包解压,并复制配置文件目录。

# 解压mycat.tar.gz,解压后的目录为mycat
➜  mycat tar -zxf mycat.tar.gz 

# 移动mycat/conf目录到根目录的conf
➜  mycat mv mycat/conf conf

# 删除mycat目录
➜  mycat rm -rf mycat

创建一个logs目录,用于存放mycat日志。

➜  mycat mkdir logs

目录完成后,结构如下:

➜  mycat tree -L 1
.
├── Dockerfile          # dockerfile文件
├── conf                        # mycat配置文件目录
├── logs                        # mycat日志目录
└── mycat.tar.gz        # mycat安装包

2.2 制作Dockerfile文件

编辑Dockerfile文件,内容如下

FROM openjdk:8

ADD ./mycat.tar.gz /usr/local/
ENV MYCAT_HOME=/usr/local/mycat
EXPOSE 8066 9066
CMD ["/usr/local/mycat/bin/mycat", "console","&"]

使用openjdk:8作为基础镜像,将mycat根目录的安装文件添加到镜像的/usr/local目录下,因为使用了ADD命令,压缩包会自动解压,设置环境变量MYCAT_HOME,暴露端口8066和9066,8066是客户端使用端口,9066为mycat管理端口。默认提供一个启动命令,使用 console选项运行在前台,保证容器启动后不会被退出。

2.3 配置Mycat

在mycat的配置在conf目录下:

  • server.xml 配置文件包含了mycat服务器参数,以及用户授权信息
  • schema.xml 配置文件包含,逻辑库、逻辑表以及分片的定义
  • rule.xml 配置文件包含,分片规则的配置

2.3.1 配置schema.xml

配置mycat/conf/schema.xml文件:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1" >
  </schema>
    <dataNode name="dn1" dataHost="localhost1" database="testdb" />
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="master:3306" user="root" password="123456" >
            <readHost host="hostS1" url="slave1:3306" user="root" password="123456" />
            <readHost host="hostS2" url="slave2:3306" user="root" password="123456" />
        </writeHost>
    </dataHost>
</mycat:schema>

以上是schema的配置,更多配置可以参考官网mycat权威指南第7章。

schema标签定义逻辑库

schema 标签用于定义 MyCat 实例中的逻辑库

  • name属性为逻辑库取名,这里为TESTDB
  • checkSQLschema 属性表示是否会去掉sql语句的schema前缀
  • sqlMaxLimit 属性,当sql语句没有设置limit时,会默认加上 limit 100,防止查询过多的结果
  • dataNode 属性用于指定逻辑库要绑定到那个dataNode数据节点上。值为dataNode的name,一个逻辑库只能绑定到一个数据节点上。

schema逻辑库标签中还可以定义逻辑表table标签,一个逻辑表可以指定多个数据节点,这里没有配置。

dataNode标签定义数据节点

数据节点就是一个数据分片,dataNode主要是向schema标签和table标签提供引用。dataNode数据节点共3个属性:

  • name 属性,为数据节点提供一个名字,方便schema和table引用。
  • dataHost属性,表示该数据节点对应的dataHost数据主机标签,值为dataHost标签的name属性
  • database属性,指定到MySQL实例的具体数据库上,因为前面我们在搭建MySQL集群时,使用的是testdb数据库,所以这里的值为testdb。

dataHost标签定义数据主机

dataHost代表多个MySQL实例的集合,这些数据库实例包括写主机(master,定义在writeHost上)和读主机(slave,定义在readHost上)。

  • name 属性,指定数据主机的名称,方便dataNode引用。
  • maxCon MySQL实例连接池的最大连接数
  • minCon MySQL实例连接池的最小连接数
  • balance 属性表示负载均衡的类型
    • balance = "0" 不开启读写分离,所有的读写操作都发到送写主机上
    • balance = "1" 开启读写分离(常用),所有写操作都发送给第一个写主机上(如果定义了多个写主机,后备写主机 stand by writeHost),所有的读操作通过负载均衡分配到其他主机,即所有的readHost和后备写主机。
    • balance = "2" 开启读写分离,所有写操作都发送到写主机上,读操作随机到所有主机上。也就是说,写主机也要承担读的任务。
    • balance = "3" 开启读写分离,读操作随机到读主机上。
  • writeType 属性,表示写主机的类型
    • writeType="0" 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个 writeHost, 重新启动后以切换后的为准。
    • writeType="1" 所有写操作都随机的发送到配置的 writeHost(已废弃)
  • switchType 属性,写主机切换方式
    • -1 表示不自动切换。
    • 1 默认值,自动切换。
    • 2 基于 MySQL 主从同步的状态决定是否切换。

heartbeat标签定义心跳检测

这个标签内指明用于和后端数据库进行心跳检查的语句。例如,MYSQL 可以使用 select user(),Oracle 可以 使用 select 1 from dual 等。

writeHost 标签定义写主机

  • host 属性,定义写主机名称,一般Master主机名为为*M1,读主机命名*S1
  • url 属性,后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式。用 JDBC 或其他的 dbDriver,则需要特殊指定。当使用 JDBC 时则可以这么写:jdbc:mysql://localhost:3306/。因为这里我们使用docker-compose启动Mycat容器,所以地址可以用主机名代理,这里master:3306 表示master数据库容器。
  • userpassword 是数据库实例的用户名密码。

readHost标签定义读主机,其属性与writeHost标签相同,需要注意的是,readHost是包裹在writeHost标签内。

2.3.2 配置server.xml

server.xml 保存了所有 mycat 需要的系统配置信息,这里我们只关系user标签。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
    
  <!--上面的内容省略-->
  
    <user name="root" defaultAccount="true">
        <property name="password">123456</property>
        <property name="schemas">TESTDB</property>
        <property name="defaultSchema">TESTDB</property>
    </user>

    <user name="user">
        <property name="password">user</property>
        <property name="schemas">TESTDB</property>
        <property name="readOnly">true</property>
        <property name="defaultSchema">TESTDB</property>
    </user>
</mycat:server>

默认情况,mycat为我们创建了两个用户,root和user,root的密码为123456。shecma属性表示该用户能够操作的逻辑数据库,对应的是schema.xml的schema标签中的name值,这里是TESTDB。如果有多个数据库,这里需要配置多个schema属性。

2.4 修改docker-compose配置文件

回到mysql目录,编辑 .env 环境变量文件,添加mycat根目录以方面docker-compose.yml文件调用

# 在.env 文件中添加MYCAT_HOME变量,指定mycat的家目录

# mycat 配置
MYCAT_HOME=/Users/zebra/docker/mysql/mycat

编辑 docker-compose.yml 配置文件

version: '3'

services: 
  master: ...
  slave1: ...
  slave2: ...
  mycat:
    restart: always
    build: ./mycat
    image: mycat:v1
    container_name: mycat
    links: 
        - ${MASTER}
        - ${SLAVE1}
        - ${SLAVE2}
    ports:
        - 8066:8066
        - 9066:9066
    volumes: 
        - ${MYCAT_HOME}/conf:/usr/local/mycat/conf
        - ${MYCAT_HOME}/logs:/usr/local/mycat/logs

在services中,增加mycat节点,build选项指定Dockerfile文件地址,这里使用相对路径,表示在当前yml配置文件目录中的mycat目录里。image为构建后的镜像名称(如果没有改镜像就构建,有就直接调用该镜像)。links选项表示mycat容器需要连接master,slave1和slave2容器(前面我们在mycat的schema.xml的配置中使用到了这些容器)。volumes 将本地数据卷挂载到容器中,这里挂载了配置目录和日志目录。

3 启动MySQL集群

现在,已经配置好了Mycat,我们使用docker-compose up -d 启动所有容器。如果之前启动过,使用docker-compose down 停止后在启动。

➜  mysql docker-compose up -d
Creating network "mysql_default" with the default driver
Building mycat
Step 1/5 : FROM openjdk:8
 ---> b190ad78b520
Step 2/5 : ADD ./mycat.tar.gz /usr/local/
 ---> 7561bd31c7c9
Step 3/5 : ENV MYCAT_HOME=/usr/local/mycat
 ---> Running in a6ed86e20223
Removing intermediate container a6ed86e20223
 ---> 2aa61a702465
Step 4/5 : EXPOSE 8066 9066
 ---> Running in 164d908610bb
Removing intermediate container 164d908610bb
 ---> ee971db034c9
Step 5/5 : CMD ["/usr/local/mycat/bin/mycat", "console","&"]
 ---> Running in 2518532eaa00
Removing intermediate container 2518532eaa00
 ---> 03b97ffc1ad2
Successfully built 03b97ffc1ad2
Successfully tagged mycat:v1
WARNING: Image for service mycat was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating master ... done
Creating slave1 ... done
Creating slave2 ... done
Creating mycat  ... done

可以看到,在启动时,因为本地没有 mycat:v1 的镜像,所以,compose会先构建该镜像。如果mycat的镜像已存在,docker-compose会直接使用该镜像,如果修改了进行的Dockerfile文件,可以使用docker-compose build 重新构建,或在启动时,通过--build选项重新构建。

外部程序可以通过8066端口连接Mycat中间件的逻辑库TESBD。

4 添加phpmyadmin应用

docker-compose.yml中添加phpmyadmin应用

version: '3'

services: 
  master: ...
  slave1: ...
  slave2: ...
  mycat: ...
  phpmyadmin:
    restart: always
    image: phpmyadmin/phpmyadmin:5.0
    container_name: myadmin
    links: 
        - master
    ports: 
        - 7500:80
    environment: 
        PMA_PORT: 3306
        PMA_HOST: master

phpmyadmin使用5.0target,连接master容器,并80端口与宿主机的7500端口相连接。这里需要注意的是,phpmyadmin如果直接连接mycat中间件,不能正常工作,需要连接mysql容器。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352