MySQL MGR单主模式搭建

备注:测试数据库版本为MySQL 8.0

这个blog我们来聊聊MySQL 组复制

概述

MySQL 是目前最流行的开源关系型数据库,国内金融行业也开始全面使用,其中 MySQL 5.7.17 提出的 MGR(MySQL Group Replication)既可以很好的保证数据一致性又可以自动切换,具备故障检测功能、支持多节点写入,MGR 是一项被普遍看好的技术。

MGR(MySQL Group Replication)是 MySQL 自带的一个插件,可以灵活部署。
MySQL MGR 集群是多个 MySQL Server 节点共同组成的分布式集群,每个 Server 都有完整的副本,它是基于 ROW 格式的二进制日志文件和 GTID 特性。

MGR架构图

image.png

MGR拓扑图

image.png

一.部署单主模式组复制

环境准备

服务器类别 IP 数据库版本
PRIMARY 10.31.1.112 8.0.20
SECONDARY 10.31.1.113 8.0.20
SECONDARY 10.31.1.114 8.0.20

1.1 安装MGR插件

在10.31.1.112/10.31.1.113/10.31.1.114中安装mgr插件

-- 安装mgr插件
mysql> install plugin group_replication soname 'group_replication.so';
Query OK, 0 rows affected (0.14 sec)
-- 检查mgr插件是否已安装
mysql> show plugins;
+---------------------------------+--------+--------------------+----------------------+---------+
| Name                            | Status | Type               | Library              | License |
+---------------------------------+--------+--------------------+----------------------+---------+
| binlog                          | ACTIVE | STORAGE ENGINE     | NULL                 | GPL     |
********
********
| group_replication               | ACTIVE | GROUP REPLICATION  | group_replication.so | GPL     |
+---------------------------------+--------+--------------------+----------------------+---------+
44 rows in set (0.01 sec)

1.2 准备配置文件

10.31.1.112的配置文件/u01/my3306/my.cnf内容如下:

[mysqld]
server_id=1
gtid_mode=ON
enforce-gtid-consistency=true
binlog_checksum=NONE
innodb_buffer_pool_size=4G
 
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
 
log_bin=binlog
log_slave_updates=ON
binlog_format=ROW
master_info_repository=TABLE
relay_log_info_repository=TABLE
 
transaction_write_set_extraction=XXHASH64
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address= "10.31.1.112:33061"
group_replication_group_seeds= "10.31.1.112:33061,10.31.1.113:33061,10.31.1.114:33061"
group_replication_bootstrap_group=off

参数说明

参数 参数说明
disabled_storage_engines 组复制数据必须存储在InnoDB事务存储引擎中,使用其它存储引擎可能导致组复制出错
因此禁用其它的存储引擎
transaction_write_set_extraction 指示服务器对于每个事务,必须收集写集并使用XXHASH64哈希算法编码。
从MySQL 8.0.2开始,此设置是默认设置,因此可以省略此行。
group_replication_group_name 告诉插件它正在加入或创建的组名为aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa。
group_replication_group_name的值必须是有效的UUID。
在二进制日志中为组复制事件设置GTID时,将在内部使用此UUID。
可以使用SELECT UUID()或Linux的uuidgen命令生成UUID。
group_replication_start_on_boot 指示插件在服务器启动时不自动启动操作。
这在设置组复制时很重要,因为它确保可以在手动启动插件之前配置服务器。
配置成员后,可以将group_replication_start_on_boot设置为on,以便在服务器引导时自动启动组复制。
group_replication_local_address 告诉插件使用网络地址10.31.1.112和端口3306与组中的其它成员进行内部通信。组复制将此地址用于涉及组通信引擎(XCom,Paxos变体)的远程实例的内部成员到成员连接。此端口必须与用于客户端连接的端口不同,并且不得用于客户端应用程序。在运行组复制时,必须为组成员之间的内部通信保留它。
group_replication_group_seeds 设置组成员的IP和端口,这些成员称为种子成员。
建立连接后,组成员身份信息将列在performance_schema.replication_group_members中。
通常,group_replication_group_seeds列表包含每个组成员的group_replication_local_address的 ip:port,
但这不是强制性的,可以选择组成员的子集作为种子。
启动该组的服务器不使用此选项,因为它是初始服务器,负责引导组。
换句话说,引导该组的服务器上的任何现有数据都是用作下一个加入成员的数据。
第二个服务器上的任何缺失数据都从引导成员上的数据中复制,然后组扩展。
加入的第三个服务器可以要求这两个服务器中的任何一个作为捐赠者,
数据被同步到新成员,然后该组再次扩展。
后续服务器在加入时重复此过程。
group_replication_bootstrap_group 指示插件是否引导该组。
此选项只能在一个服务器实例上使用,通常是第一次引导组时(或者在整个组关闭并重新备份的情况下)。
如果多次引导组,例如当多个服务器实例设置了此选项时,
则可以创建一个人工脑裂的情景,存在两个具有相同名称的不同组。

另外两台服务器
10.31.1.113、10.31.1.114的配置文件中只有server_id和group_replication_local_address两个参数值不同,其它配置参数与10.31.1.112相同:

# 10.31.1.113:
server_id=2
group_replication_local_address= "10.31.1.113:33061"
 
#10.31.1.114:
server_id=3
group_replication_local_address= "10.31.1.114:33061"

1.3重启mysql服务

mysqladmin -uroot -p -S /u01/my3306/mysql.sock shutdown  
/u01/my3306/bin/mysqld_safe --defaults-file=/u01/my3306/my.cnf --user=mysql &

1.4启动组复制

在10.31.1.112上执行以下步骤启动组复制。组复制使用异步复制协议实现分布式恢复,在将组成员加入组之前同步数据。分布式恢复过程依赖于名为group_replication_recovery的复制通道,该通道用于将事务从捐赠者转移到加入该组的成员。因此需要设置具有正确权限的复制用户,以便组复制可以建立直接的成员到成员恢复复制通道。

1.4.1 创建复制用户

create user 'repl'@'%' identified with 'mysql_native_password' by '123456';
grant replication slave on *.* to 'repl'@'%';

1.4.2 配置用于新成员与捐赠者之间异步复制的复制通道

change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';

1.4.3 启动组复制

要启动该组,需指示服务器S1引导该组,然后启动组复制。此引导程序应仅由单个服务器完成,该服务器启动组并且只执行一次。

set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;

1.4.4 确认组复制是否启动成功

一旦START GROUP_REPLICATION语句返回,该组就已启动。可以检查该组现在是否已创建,并且其中包含一个成员:

mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
1 row in set (0.01 sec)

此表中的信息确认组中的成员具有唯一标识符 c258c587-d22c-11ea-a73e-000c293fa60d,它是ONLINE并且在10.31.1.112上侦听端口3306上的客户端连接。

1.4.5 向组中添加实例

10.31.1.112运行xtrabackup全备

mkdir -p /backup/mysql/20200731/fulldb
xtrabackup --defaults-file=/u01/my3306/my.cnf  --user=root --password=abc123 --port=3306 --backup --target-dir=/backup/mysql/20200731/fulldb

将112备份文件传输到113、114两台服务器上

scp -r ./fulldb/ mysql@10.31.1.113:/backup/mysql/20200731/
scp -r ./fulldb/ mysql@10.31.1.114:/backup/mysql/20200731/

在113、114上执行如下命令

-- 停止mysql
mysqladmin -uroot -p -S /u01/my3306/mysql.sock shutdown
-- 删除datadir下的所有文件
cd /u01/my3306/data/
rm -rf *
-- 准备全备份的日志:
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/20200731/fulldb
-- 全备份准备
xtrabackup --prepare --target-dir=/backup/mysql/20200731/fulldb
-- 拷回数据
xtrabackup -user=root --password=abc123 --port=3306 --datadir=/u01/my3306/data/ --copy-back --target-dir=/backup/mysql/20200731/fulldb/
-- 启动mysql
/u01/my3306/bin/mysqld_safe --defaults-file=/u01/my3306/my.cnf --user=mysql &

将113、114加入复制组

-- 重置relay log info
reset slave all;
-- 设置复制通道
change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
-- 添加到组
start group_replication;
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.01 sec)

参数说明

参数 参数说明
CHANNEL_NAME 通道名称。组复制插件创建两个复制通道。
group_replication_recovery用于与分布式恢复阶段相关的复制更改。
group_replication_applier用于来自组传入的更改,是应用直接来自组的事务的通道。
MEMBER_ID 组成员实例的server_uuid。
MEMBER_HOST 组成员主机名。如果配置了report_host参数,这里显示IP地址。
MEMBER_ROLE 成员角色,主为PRIMARY,从为SECONDARY。
MEMBER_VERSION 成员数据库实例版本。
MEMBER_STATE 成员状态,取值和含义如下表所示:
ONLINE:表示该成员可正常提供服务
RECOVERING:表示当前成员正在从其它节点恢复数据
OFFLINE: 表示组复制插件已经加载,但是该成员不属于任何一个复制组
ERROR: 表示成员在recovery阶段出现错误或者从其它节点同步状态中出现错误
UNREACHABLE:成员处于不可达状态,无法与之进行网络通讯

1.5 UNREACHABLE处理案例

-- 113
ps -ef | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill -9
-- 112上查询
select * from performance_schema.replication_group_members;
-- 114 
ps -ef | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill -9
-- 112上查询
-- 这个时候,UNREACHABLE状态将一直持续。而且此时,集群不满足2N + 1,集群已经不可用(即使有主成员,它也是不可写的)
select * from performance_schema.replication_group_members;
[mysql@10.31.1.113 data]$ ps -ef | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill -9
[1]+  Killed                  /u01/my3306/bin/mysqld_safe --defaults-file=/u01/my3306/my.cnf --user=mysql
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
2 rows in set (0.00 sec)
[mysql@10.31.1.114 data]$ ps -ef | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill -9
[1]+  Killed                  /u01/my3306/bin/mysqld_safe --defaults-file=/u01/my3306/my.cnf --user=mysql
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | UNREACHABLE  | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
2 rows in set (0.00 sec)

恢复组复制步骤
1.在112上创建一个新的复制组

stop group_replication;
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;

2.启动113、114实例

/u01/my3306/bin/mysqld_safe --defaults-file=/u01/my3306/my.cnf --user=mysql &

3.将113、114重新加入新的复制组

change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
start group_replication;

二.组复制监控

组复制监控依赖performance_schema下几张表:

performance_schema.replication_group_members
performance_schema.replication_group_member_stats
performance_schema.replication_connection_status
performance_schema.replication_applier_status

performance_schema.replication_group_members表
用于监视作为组成员的不同服务器实例的状态。只要视图更改,就会更新表中的信息。例如,因新成员加入而动态更改组的配置时。此时,服务器交换一些元数据以使其自身同步并继续一起协作。信息在作为复制组成员的所有服务器实例之间共享,因此可以从任何成员查询有关所有组成员的信息。此表可用作获取复制组状态的高级视图。

performance_schema.replication_group_member_stats表
提供与认证过程相关的组级信息,以及由复制组的每个成员接收和发起的事务的统计信息。信息在作为复制组成员的所有服务器实例之间共享,因此可以从任何成员查询有关所有组成员的信息。刷新远程成员的统计信息由group_replication_flow_control_period配置参数中指定的消息周期控制(缺省值为1秒),因此可能与本地收集的查询成员的统计信息略有不同。

列说明
CHANNEL_NAME 组复制通道名称。
VIEW_ID 复制组当前视图ID。
MEMBER_ID 组成员的server_uuid。
COUNT_TRANSACTIONS_IN_QUEUE 队列中等待冲突检测的事务数。一旦事务通过了冲突检查,它们就会排队等待应用。
COUNT_TRANSACTIONS_CHECKED 通过冲突检查的事务数。
COUNT_CONFLICTS_DETECTED 未通过冲突检测检查的事务数。
COUNT_TRANSACTIONS_ROWS_VALIDATING 冲突检查数据库的大小。
TRANSACTIONS_COMMITTED_ALL_MEMBERS 已在复制组的所有成员上成功提交的事务,显示为GTID集。这是以固定的时间间隔更新的。
LAST_CONFLICT_FREE_TRANSACTION 最后一次冲突,被释放的事务标识符。
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE 此成员从复制组收到的等待应用的事务数。
COUNT_TRANSACTIONS_REMOTE_APPLIED 此成员从复制组中收到并已应用的事务数。
COUNT_TRANSACTIONS_LOCAL_PROPOSED 源自此成员并发送给复制组的事务数。
COUNT_TRANSACTIONS_LOCAL_ROLLBACK 源自此成员并被复制组回滚的事务数。

该表字段对于监视组中连接成员的性能很重要。例如,假设组中的一个成员总是在其队列中报告与其它成员相比存在大量事务。这意味着该成员存在延迟,并且无法与该组的其它成员保持同步。根据此信息,可能决定从组中删除该成员,或者延迟处理该组其它成员上的事务,以减少排队事务的数量。此信息还可以帮助决定如何调整组复制插件的流控制。
performance_schema.replication_connection_status
显示有关组复制的信息,例如已从组接收并在应用程序队列(中继日志)中排队的事务。performance_schema.replication_applier_status显示与组复制相关的通道和线程的状态。如果有许多不同的工作线程应用事务,那么该表也可用于监视每个工作线程正在执行的操作。

列说明
CHANNEL_NAME 组复制通道名称。始终存在默认复制通道,可以添加更多复制通道。
GROUP_NAME 如果此服务器是组的成员,则显示服务器所属的组的名称。
SOURCE_UUID 组标识符。
THREAD_ID I/O线程ID。
SERVICE_STATE ON表示线程存在且处于活动状态或空闲状态,OFF表示线程不再存在,CONNECTING表示线程存在并连接到主服务器。
COUNT_RECEIVED_HEARTBEATS 成员自上次重启、重置、或者发出了CHANGE MASTER TO语句后,收到的心跳信号总数。
LAST_HEARTBEAT_TIMESTAMP 成员收到最新心跳信号的时间戳。
RECEIVED_TRANSACTION_SET 已经被接收的GTID集。
LAST_ERROR_NUMBER 导致I/O线程停止的最新错误的错误号,0表示无错误。RESET MASTER或RESET SLAVE将重置该列中显示的值。
LAST_ERROR_MESSAGE 导致I/O线程停止的最新错误的错误消息,空字符串表示无错误。RESET MASTER或RESET SLAVE将重置该列中显示的值。
LAST_ERROR_TIMESTAMP 最近发生I/O错误的时间戳。
LAST_QUEUED_TRANSACTION 排队到中继日志的最后一个事务的GTID。
LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP 中继日志中排队的最后一个事务在原始主服务器上提交的时间戳。
LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP 中继日志中排队的最后一个事务在当前服务器上提交的时间戳。
LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP I/O线程将最后一个事务放入中继日志队列的时间戳。
LAST_QUEUED_TRANSACTION_END_QUEUE_TIMESTAMP 最后一个事务排队到中继日志文件的时间戳。
QUEUEING_TRANSACTION 中继日志中当前排队事务GTID。
QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP 当前排队事务在原始主服务器上提交的时间戳。
QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP 当前排队事务在当前服务器上提交的时间戳。
QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP 当前排队事务的第一个事件何时被I/O线程写入中继日志。

performance_schema.replication_applier_status表

列说明
CHANNEL_NAME 组复制通道名称。始终存在默认复制通道,可以添加更多复制通道。
SERVICE_STATE 当复制通道的应用程序线程处于活动状态或空闲状态时显示ON,OFF表示应用程序线程未处于活动状态。
REMAINING_DELAY 延迟复制时则此字段指示剩余的延迟秒数,其它情况此字段为NULL。
COUNT_TRANSACTIONS_RETRIES 显示由于SQL线程无法应用事务而进行的重试次数。给定事务的最大重试次数由slave_transaction_retries系统变量设置。replication_applier_status_by_worker表显示有关单线程或多线程从库的事务重试的详细信息。

三.容错示例

以三成员为例,验证以下场景下对整个集群的影响:
一个SECONDARY实例正常shutdown。
一个SECONDARY实例异常shutdown。
PRIMARY实例正常shutdown。
PRIMARY实例异常shutdown。

因为只有三个成员,这四种场景均能够保证最大票数。无法保证最大票数时,如上面例子中三个成员中的两个异常宕机,则整个集群无法正常读写,需要管理员人为介入解决问题。这种情况显然不属于容错的范畴。

3.1 一个SECONDARY实例正常shutdown

3.1.1 主库上执行长时间运行的事务

delimiter //
create procedure p1(a int)
begin
? ?declare i int default 1;
? ?while i<=a do
? ? ? insert into t1 select null;
? ? ? set i=i+1;
end while;
end;
//
delimiter ;
 
-- 在112上执行
use test;
truncate table t1;
call p1(100000);

3.1.2 在上一步执行期间停止一个从库

# 停止114的MySQL实例
mysqladmin -uroot -pabc123 shutdown

3.1.3 检查剩余组复制成员状态

-- 在112上执行
select * from performance_schema.replication_group_members;
-- 在113上检查复制事务和数据
select * from performance_schema.replication_group_member_stats where member_id='1e483071-d2f8-11ea-9377-000c297ccd64'\G
-- 112运行
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
2 rows in set (0.00 sec)
-- 113运行
mysql> select * from performance_schema.replication_group_member_stats where member_id='1e483071-d2f8-11ea-9377-000c297ccd64'\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:4
                                 MEMBER_ID: 1e483071-d2f8-11ea-9377-000c297ccd64
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 99071
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 28392
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 08260f93-cbe5-11ea-bd0d-000c293fa60d:1-2,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-370711,
c258c587-d22c-11ea-a73e-000c293fa60d:1-2
            LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:399102
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 99072
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
1 row in set (0.01 sec)

可以看到,一个SECONDARY实例正常shutdown,对应用来说只是少了只读实例。复制组中的剩余成员状态依然是ONLINE。主库正常读写,从库正常复制,并且没有积压的事务(COUNT_TRANSACTIONS_IN_QUEUE为0)。

3.1.4 恢复shutdown的实例

-- 114上执行
mysqld_safe --defaults-file=/u01/my3306/my.cnf &

114上检查组复制成员状态:

mysql> select * from performance_schema.replication_group_members;
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier |           |             |        NULL | OFFLINE      |             |                |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
1 row in set (0.00 sec)

此时114的状态为OFFLINE,已经从复制组中被移除。在114检查复制事务和数据:

mysql> select * from performance_schema.replication_group_member_stats where member_id='4109184b-d2f8-11ea-b1d5-000c295d5891'\G
Empty set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |   5628 |     5628 |
+--------+--------+----------+
1 row in set (0.00 sec)

可以看到,此时performance_schema.replication_group_member_stats表中已经没有此成员相关的信息,实例停止时插入了5628条数据。
将114重新加入复制组:

change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
start group_replication;
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | RECOVERING   | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)

mysql> select * from performance_schema.replication_group_member_stats where member_id='4109184b-d2f8-11ea-b1d5-000c295d5891'\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:5
                                 MEMBER_ID: 4109184b-d2f8-11ea-b1d5-000c295d5891
               COUNT_TRANSACTIONS_IN_QUEUE: 1
                COUNT_TRANSACTIONS_CHECKED: 0
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 0
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 
            LAST_CONFLICT_FREE_TRANSACTION: 
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 0
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
1 row in set (0.00 sec)

114开始处于RECOVERING状态,表明它正在追赶组的复制进度,当赶上后,它的状态将变为ONLINE。由此可见,一个SECONDARY实例正常shutdown基本对复制组没有影响(就是少了一个读成员)。当把它重新加入组中,落后的事务自动恢复,直至赶上状态自动变为ONLINE。

3.2 一个SECONDARY实例异常shutdown

3.2.1 主库上执行长时间运行的事务

-- 在112上执行
use test;
truncate table t1;
call p1(100000);

3.2.3 在上一步执行期间停止一个从库

# 停止114的MySQL实例
ps -ef | grep mysqld | grep -v grep | awk {'print $2'} | xargs kill -9

3.2.3 检查剩余组复制成员状态

-- 112上检查复制组成员状态
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
2 rows in set (0.00 sec)

-- 在113检查复制事务和数据
mysql> select * from performance_schema.replication_group_member_stats where member_id='1e483071-d2f8-11ea-9377-000c297ccd64'\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:6
                                 MEMBER_ID: 1e483071-d2f8-11ea-9377-000c297ccd64
               COUNT_TRANSACTIONS_IN_QUEUE: 1
                COUNT_TRANSACTIONS_CHECKED: 129976
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 18408
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 08260f93-cbe5-11ea-bd0d-000c293fa60d:1-2,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-411601,
c258c587-d22c-11ea-a73e-000c293fa60d:1-2
            LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:430008
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 129977
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
1 row in set (0.00 sec)

可以看到,一个SECONDARY实例异常shutdown,对复制组的影响与正常shutdown别无二致。

3.2.4 恢复shutdown的实例

 -- 启动114的MySQL实例:
mysqld_safe --defaults-file=/u01/my3306/my.cnf &

在114上检查组复制成员状态:

mysql> select * from performance_schema.replication_group_members;
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier |           |             |        NULL | OFFLINE      |             |                |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
1 row in set (0.00 sec)

此时114的状态为OFFLINE,已经从复制组中被移除。 在114检查复制事务和数据:

mysql> select * from performance_schema.replication_group_member_stats where member_id='4109184b-d2f8-11ea-b1d5-000c295d5891'\G
Empty set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |   4491 |     4491 |
+--------+--------+----------+
1 row in set (0.00 sec)

可以看到,此时performance_schema.replication_group_member_stats表中已经没有此成员相关的信息,实例停止时插入了4491条数据。
将114重新加入复制组:

change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
start group_replication;

再次检查成员状态、复制事务和数据:

mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | RECOVERING   | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)

mysql> select * from performance_schema.replication_group_member_stats where member_id='4109184b-d2f8-11ea-b1d5-000c295d5891'\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:7
                                 MEMBER_ID: 4109184b-d2f8-11ea-b1d5-000c295d5891
               COUNT_TRANSACTIONS_IN_QUEUE: 1
                COUNT_TRANSACTIONS_CHECKED: 0
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 0
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 
            LAST_CONFLICT_FREE_TRANSACTION: 
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 0
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
1 row in set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |  50035 |    50035 |
+--------+--------+----------+
1 row in set (0.03 sec)

114正处于RECOVERING状态,表明它正在追赶组的复制进度,当赶上后,它的状态将变为ONLINE。由此可见,一个SECONDARY实例的正常shutdown和异常shutdown,对复制组的影响和恢复过程都没有任何区别。其实就多了一个MySQL实例的恢复过程,这是在重新启动114时自动进行的,对用户是完全透明。

3.3 PRIMARY实例正常shutdown

3.3.1 主库上执行长时间运行的事务

-- 在112上执行
use test;
truncate table t1;
call p1(100000);

3.3.2 在上一步执行期间停止主库

# 停止112的MySQL实例
mysqladmin -uroot -pabc123 shutdown

3.3.3 检查剩余组复制成员状态

在113、114上检查复制组成员状态:

-- 113执行
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
2 rows in set (0.00 sec)

可以看到,当PRIMARY实例正常shutdown,复制组中的剩余成员状态依然是ONLINE,并且自动把其中一个SECONDARY(本例中为113)提升为PRIMARY。在113、114上检查复制事务和数据:

-- 113
mysql> select * from performance_schema.replication_group_member_stats\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:8
                                 MEMBER_ID: 1e483071-d2f8-11ea-9377-000c297ccd64
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 208570
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 08260f93-cbe5-11ea-bd0d-000c293fa60d:1-2,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-508603,
c258c587-d22c-11ea-a73e-000c293fa60d:1-2
            LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:508603
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 208573
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
*************************** 2. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:8
                                 MEMBER_ID: 4109184b-d2f8-11ea-b1d5-000c295d5891
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 8568
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 08260f93-cbe5-11ea-bd0d-000c293fa60d:1-2,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-508603,
c258c587-d22c-11ea-a73e-000c293fa60d:1-2
            LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:508603
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 8568
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
2 rows in set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |   8567 |     8567 |
+--------+--------+----------+
1 row in set (0.01 sec)
-- 114 
mysql> select * from performance_schema.replication_group_member_stats\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:8
                                 MEMBER_ID: 1e483071-d2f8-11ea-9377-000c297ccd64
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 208570
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 08260f93-cbe5-11ea-bd0d-000c293fa60d:1-2,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-508603,
c258c587-d22c-11ea-a73e-000c293fa60d:1-2
            LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:508603
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 208573
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
*************************** 2. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:8
                                 MEMBER_ID: 4109184b-d2f8-11ea-b1d5-000c295d5891
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 8568
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 08260f93-cbe5-11ea-bd0d-000c293fa60d:1-2,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-508603,
c258c587-d22c-11ea-a73e-000c293fa60d:1-2
            LAST_CONFLICT_FREE_TRANSACTION: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:508603
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 8568
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
2 rows in set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |   8567 |     8567 |
+--------+--------+----------+
1 row in set (0.00 sec)

3.3.4 恢复shutdown的实例

启动112的MySQL实例:

mysqld_safe --defaults-file=/u01/my3306/my.cnf &

在112上检查组复制成员状态:

mysql> select * from performance_schema.replication_group_members;
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier |           |             |        NULL | OFFLINE      |             |                |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+
1 row in set (0.00 sec)

此时112的状态为OFFLINE,已经从复制组中被移除。在112检查复制事务和数据:

mysql> select * from performance_schema.replication_group_member_stats where member_id='c258c587-d22c-11ea-a73e-000c293fa60d'\G 
Empty set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |   8567 |     8567 |
+--------+--------+----------+
1 row in set (0.01 sec)

可以看到,此时performance_schema.replication_group_member_stats表中已经没有此成员相关的信息,实例停止时插入了8567条数据。
将112重新加入复制组:

change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
start group_replication;

再次检查成员状态、复制事务和数据:

mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1e483071-d2f8-11ea-9377-000c297ccd64 | 10.31.1.113     |        3306 | ONLINE       | PRIMARY     | 8.0.20         |
| group_replication_applier | 4109184b-d2f8-11ea-b1d5-000c295d5891 | 10.31.1.114     |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
| group_replication_applier | c258c587-d22c-11ea-a73e-000c293fa60d | 10.31.1.112    |        3306 | ONLINE       | SECONDARY   | 8.0.20         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)

mysql> select * from performance_schema.replication_group_member_stats where member_id='c258c587-d22c-11ea-a73e-000c293fa60d'\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15961790962628600:9
                                 MEMBER_ID: c258c587-d22c-11ea-a73e-000c293fa60d
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 0
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 
            LAST_CONFLICT_FREE_TRANSACTION: 
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 0
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
1 row in set (0.00 sec)

mysql> select min(a),max(a),count(*) from test.t1;
+--------+--------+----------+
| min(a) | max(a) | count(*) |
+--------+--------+----------+
|      1 |   8567 |     8567 |
+--------+--------+----------+
1 row in set (0.00 sec)

112处于ONLINE状态,但角色已经变成了SECONDARY。
此时112变为一个只读成员:

mysql> show variables like '%read_only%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_read_only      | OFF   |
| read_only             | ON    |
| super_read_only       | ON    |
| transaction_read_only | OFF   |
+-----------------------+-------+
4 rows in set (0.01 sec)

而113成为读写成员(主库):

mysql> show variables like '%read_only%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_read_only      | OFF   |
| read_only             | OFF   |
| super_read_only       | OFF   |
| transaction_read_only | OFF   |
+-----------------------+-------+
4 rows in set (0.01 sec)

由此可见,当PRIMARY实例正常shutdown,组复制会把一个SECONDARY提升为新的PRIMARY。而原来的PRIMARY在重新加入组后立即ONLINE,角色变为SECONDARY。这一切都是自动进行的,应用需要做的是重新连接新的PRIMARY实例,以便继续执行读写事务。

3.4 PRIMARY实例异常shutdown

此处略过,经过测试,异常shutdown与 3.3 正常关闭相同。

参考文献:

1.https://blog.csdn.net/wzy0623/article/details/95619837
2.https://dev.mysql.com/doc/refman/8.0/en/group-replication-configuring-instances.html

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