备注:测试数据库版本为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架构图
MGR拓扑图
一.部署单主模式组复制
环境准备
服务器类别 | 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