MySQL组复制(一)

概述

MySQL Group Replication是MySQL5.7引进的高可用扩展,以插件形式提供。复制组包含多个成员,每个成员都有完整的数据副本,成员之间通过广播消息互相交互。

在多个成员互相交互的过程中会对事务进行冲突检测,优先进行提交的事务顺利完成提交,其它冲突事务则进行回退。在高并发的场景下大量事务回退导致性能降低,因此官方建议对同一记录的修改应该放在一个节点上,利用本地锁进行同步等待,避免事务冲突造成大量回滚。

下图描述了 MySQL 组复制协议: Group Replication

MGR基于现有的MySQL复制体系,利用二进制日志、基于行的日志记录和全局事务标识等功能。下图显示了MySQL Group Replication的结构图 Group Replication Plugin Block Diagram

MySQL Group Replication plugin包含一组用于捕获、应用、生命周期管理的API,它们控制插件如何与MySQL Server进行交互。下面则是一组组件,当通知路由到它们时,它们会进行相应处理。Capture负责跟踪与正在执行的事务的上下文;applier组件负责在数据库上执行远程事务;recovery组件管理分布式恢复,并负责通过选择数据源、管理catch up过程和对数据源失败作出反应获取加入组的服务器信息。

replication protocol协议模块包含复制协议的特定逻辑。它处理冲突检测,接收事务并向组传播事务

最后两层是组通信系统(GCS)API,以及基于paxos的组通信引擎(xcom)的实现。

MySQL Group Replication基于Paxos分布式算法的实现,以提供Server之间的分布式协调。因此它需要绝大部分Server(n/2+1)处于活动状态才能做到仲裁,从而做出决定。组复制具有组成员身份服务,用于定义哪些服务器联机并参与组,称之为视图,每个成员都维护着相同的视图,成员不仅就事务提交达成一致,而且必须对当前视图达成一致,成员的离开或加入都需要更新视图。

组复制模式

单主模式

在单主模式(group_replication_single_primary_mode=ON)中,只有主节点能够接收读写请求,其它成员都为只读模式。新加入组的都会了解到主节点信息,并自动设置为只读模式。

单主模式相对于多主模式,一致性检查不太严格,并且不需要格外小心处理DDL语句。因此,需要通过group_replication_enforce_update_everywhere_checks=OFF来禁用严格的一致性检查。

下列情况会触发重新选举主节点:

  • 主节点故障脱离复制组,会自动进行新主选举
  • 8.0.13或更高版本,使用SELECT group_replication_set_as_primary(MEMBER_ID)切换主节点
  • 8.0.13或更高版本,使用SELECT group_replication_switch_to_single_primary_mode(MEMBER_ID)由多主模式切换到单主模式运行

New Primary Election

当重新选举主节点时,可能存在积压的更改,这些更改已经应用于旧的主节点,新主节点并未应用。在新主追上旧主前,读写事务可能导致冲突并回滚,只读事务也可能读取到过时数据。组复制的流控机制可以平衡快成员和慢成员之间的差异,减少这种情况的发生。

成员在选举时,主要考虑下列三个因素:

  • 首先考虑MySQL版本差异
  • MySQL版本一致则考虑group_replication_member_weight定义的权重
  • 最后考虑根据成员UUID排序选择第一个成员

多主模式

在多主模式(group_replication_single_primary_mode=OFF)中,所有节点都可以接收读写请求。如果成员停止接收写入事务,连接到该事务的客户端可以重定向到其它节点进行处理。组复制本身不支持客户端的Failover,需要通过中间件来实现。 Client Failover

在多主模式下,需要检查事务与模式的兼容性,因此我们需要设置group_replication_enforce_update_everywhere_checks=ON来开启一致性检查:

  • 如果在 SERIALIZABLE 隔离级别下执行事务,则与组同步时其提交将失败
  • 如果一个事务对一个具有级联约束的外键的表执行,那么它在与组同步时提交失败

多主模式执行DDL操作需要格外注意,同一对象的DDL语句和DML语句应该在同一节点上进行,否则当操作中断或部分完成时,可能会导致数据不一致。

MGR配置

当前我们已经安装了三个MySQL8.0.23的实例,在此基础上来进行MGR组复制的配置。

IP PORT ROLE
10.255.210.9 3306 primary
10.255.210.10 3306 readonly
10.255.210.10 3306 readonly

组复制限制

  • INNODB存储引擎
  • 表上需要存在主键或非空唯一键
  • MGR最大支持9个成员
  • binlog_checksum在8.0.20及之前只能设置为NULL,8.0.21开始可以设置为CRC32
  • 多主模式下可能导致死锁,比如多个节点发起select for update,由于多节点锁不共享,很容易导致死锁的情况
  • 不支持复制过滤器

参数配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
binlog_checksum=NONE
log_bin=/service/binlog/mysql-bin
log_slave_updates=ON
binlog_format=ROW
master_info_repository=TABLE
relay_log_info_repository=TABLE
transaction_write_set_extraction=XXHASH64
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=8
loose-group_replication_group_name="e91c4508-d45a-11e9-911e-005056ab71f1"
loose-group_replication_start_on_boot=OFF
loose-group_replication_local_address="10.255.210.9:3307"
loose-group_replication_group_seeds="10.255.210.9:3307,10.255.210.10:3307,10.255.210.15:3307"
loose-group_replication_bootstrap_group=off
loose-group_replication_single_primary_mode=true
loose-group_replication_enforce_update_everywhere_checks=false
loose-group_replication_recovery_get_public_key=on

Tips:server_id,loose-group_replication_local_address,report-host三个参数每个节点不能一样

创建用户

1
2
3
4
5
6
mysql> SET SQL_LOG_BIN=0;
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'password';
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
mysql> GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
mysql> FLUSH PRIVILEGES;
mysql> SET SQL_LOG_BIN=1;

创建复制通道

1
mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';

安装组复制插件

1
mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';

选择一个节点作为主节点来引导复制组

1
2
3
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;

其它节点加入组复制

1
mysql> START GROUP_REPLICATION;

查看复制组

1
2
3
4
5
6
7
8
root@(none) 02:12:  SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+---------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST   | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+---------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 27bb725e-5ecf-11eb-9d27-0050569cda44 | 10.255.210.10 |        3306 | ONLINE       | SECONDARY   | 8.0.23         |
| group_replication_applier | 56b75f4e-5eba-11eb-8575-0050569cdadc | 10.255.210.9  |        3306 | ONLINE       | PRIMARY     | 8.0.23         |
| group_replication_applier | d1fbe050-5ecf-11eb-a88d-0050569c8f5e | 10.255.210.15 |        3306 | ONLINE       | SECONDARY   | 8.0.23         |
+---------------------------+--------------------------------------+---------------+-------------+--------------+-------------+----------------+

组复制状态

状态 描述
ONLINE 成员已准备好充当功能齐全的组成员,这意味着客户端可以连接并开始执行事务
RECOVERING 该成员正在成为小组的积极成员,目前正在执行恢复过程,从数据源复制相关数据
OFFLINE 组复制插件已加载,但成员不属于任何组
ERROR 成员处于错误状态,不能作为组成员正常运行,group_replication_exit_state_action参数可以定义错误后的操作
UNREACHABLE 当本地故障检测器怀疑无法访问给定服务器时,例如它是非自愿断开连接的,它会将服务器的状态显示为UNREACHABLE
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus