MySQL MGR
1 MGR集群模式介绍
MySQL是目前最流行的开源关系型数据库,国内金融行业也开始全面使用,其中MySQL 5.7.17提出的MGR(MySQL Group Replication)既可以很好的保证数据一致性又可以自动切换,具备故障检测功能、支持多节点写入,MGR是一项被普遍看好的技术。
MGR(MySQLrGroup Replication)是MySQL自带的一个插件,可以灵活部署。MySQL MGR集群是多个MySQL Server节点共同组成的分布式集群,每个Server都有完整的副本,它是基于ROW格式的二进制日志文件和GTID特性。

1.1 MGR的优点
- 强一致性,基于原生复制及paxos协议的组复制技术,并以插件的方式,提供一致数据安全保证;

- 高容错性,只要不是大多数节点就可以继续工作,有自动监测机制,当不同节点产生资源争用冲突时,不会出现错误,按照先到者先得原则处理,并且内置了自动化脑裂防护机制;

- 高扩展性,节点的新增和移除都是自动的,新节点加入后,会自动从其他节点上同步状态,知道新节点和其他节点保持一致,如果某节点被移除,其他节点自动更新信息,自动维护新的组信息;
- 高灵活性,有单主模式和多主模式,单主模式下,所有更新操作都在主上进行;多主模式下,所有server都可以同时处理更新操作。
1.2 MGR的使用约束
- 仅支持InnoDB表,并且每张表一定要有一个主键,用于做write set的冲突检测;
- 必须打开GTID特性,二进制日志格式必须设置为ROW,用于选主与writeset;主从状态信息存于表中(--master-info-repository=TABLE、--relay-log-info-repository=TABLE),--log-slave-updates打开;
- MGR不支持大事务,事务大小最好不超过143MB,当事务过大,无法在5秒的时间内通过网络在组成员间复制消息,则可能会怀疑成员失败了,然后将其驱逐出局
- 目前一个MGR集群最多支持9个节点
- 不支持外键于save point特性,无法做全局间的约束检测与部分事务回滚
- 二进制日志不支持Binlog Event Checksum
1.3 MGR适用场景
- 金融交易,重要数据存储,对主从一致性要高的场景
- 核心数据总量未过亿
- 读多写少的应用场景,如互联网电商
2 MGR集群搭建
2.1 集群搭建过程
-
安装MySQL8.0(自行百度)
-
设置网络相关
# 修改hosts cat >> /etc/hosts << EOF 10.206.0.6 n0 10.206.0.16 n1 10.206.0.4 n2 EOF # 修改对应的主机名 hostnamectl set-hostname n0 hostnamectl set-hostname n1 hostnamectl set-hostname n2 # 大坑1: # 临时关闭selinux防火墙,开启端口将无法访问,开发环境可以这样用 # 生产环境这块安全配置麻烦点,咱们后面再说 setenforce 0 # 放行端口,3306MySQL默认端口,24901MGR通信端口 firewall-cmd --zone=public --add-port=3306/tcp --permanent firewall-cmd --zone=public --add-port=24901/tcp --permanent firewall-cmd --reload -
调整配置文件
- Master节点
# 安装完成,追加mysql sudo cat >> /etc/my.cnf << 'EOF' # 使用mysql_native_password密码策略,方式navicat连不上MySQL default_authentication_plugin = mysql_native_password # 设置MySQL插件的所在目录,因为MGR基于插件,所以必须设置插件路径 plugin_dir = /usr/lib64/mysql/plugin # 服务器编号 server_id = 1 # 开启binlog的GTID模式 gtid_mode = ON # 开启后MySQL只允许能够保证事务安全,并且能够被日志记录的SQL语句被执行 enforce_gtid_consistency = ON # 关闭binlog校验 binlog_checksum = NONE # 定义用于事务期间哈希写入提取的算法,组复制模式下必须设置为 XXHASH64 transaction_write_set_extraction = XXHASH64 # 确定组复制恢复时是否应该应用SSL,通常设置为开,但是默认设置为关 loose-group_replication_recovery_use_ssl = ON # 该服务器的实例所在复制组的名称,必须是有效的UUID,所有节点必须同步 loose-group_replication_group_name = "97fdde72-4954-4790-b757-9f861063a77e" # 确定服务器是否应该在服务启动期间开启组复制 loose-group_replication_start_on_boot = OFF # 大坑2: # 为复制组中其他的成员提供的网络地址,指定为“主机:端口”的格式化字符串。 # 很多人想当然认为端口应该是3306,起始不然,MGR需要开启新端口24901同步交换 # 所以这里不要写错,同时,前面我们配置了hosts文件做了主机名与IP的映射,这里直接写主机名即可 loose-group_replication_local_address = "n0:24901" # 用于建立新成员到组的连接组成员列表。 # 这个列表指定为由分隔号间隔的组成员网络地址列表,类似 host1:port1、host2:port2 的格式。 # 同样采用no~n2的主机名替代 loose-group_replication_group_seeds = "n0:24901,n1:24901,n2:24901" # 配置此服务器为引导组,这个选项必须仅在一台服务器上设置, # 并且仅当第一次启动组或者重新启动整个组时。成功引导组启动后,将此选项设置为关闭。 loose-group_replication_bootstrap_group = OFF EOF # 启动MySQL systemctl start mysqld- Replication节点-1
# 安装完成,追加mysql sudo cat >> /etc/my.cnf << EOF default_authentication_plugin = mysql_native_password # plugin_dir = /usr/lib64/mysql/plugin # 设置唯一的服务器编号 server_id = 2 gtid_mode = ON enforce_gtid_consistency = ON binlog_checksum = NONE # 这个参数决定primary节点到secondary节点的请求是否基于RSA秘钥对的密码交换所需公钥 loose-group_replication_recovery_get_public_key = ON loose-group_replication_recovery_use_ssl = ON loose-group_replication_group_name = "97fdde72-4954-4790-b757-9f861063a77e" loose-group_replication_start_on_boot = OFF # 设置本机地址n1:24901 loose-group_replication_local_address = "n1:24901" loose-group_replication_group_seeds = "n0:24901,n1:24901,n2:24901" loose-group_replication_bootstrap_group = OFF EOF # 启动MySQL systemctl start mysqld- Replication节点-2
# 安装完成,追加mysql sudo cat >> /etc/my.cnf << EOF default_authentication_plugin = mysql_native_password # plugin_dir = /usr/lib64/mysql/plugin # 设置唯一的服务器编号 server_id = 3 gtid_mode = ON enforce_gtid_consistency = ON binlog_checksum = NONE # 这个参数决定primary节点到secondary节点的请求是否基于RSA秘钥对的密码交换所需公钥 loose-group_replication_recovery_get_public_key = ON loose-group_replication_recovery_use_ssl = ON loose-group_replication_group_name = "97fdde72-4954-4790-b757-9f861063a77e" loose-group_replication_start_on_boot = OFF # 设置本机地址n2:24901 loose-group_replication_local_address = "n2:24901" loose-group_replication_group_seeds = "n0:24901,n1:24901,n2:24901" loose-group_replication_bootstrap_group = OFF EOF # 启动MySQL systemctl start mysqld -
登录mysql,进行修改密码并设置主从同步账号
# 修改root密码为asAS123456 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'asAS123456!'; # 创建rpl_user账号,此账户用来实现主从同步 CREATE USER rpl_user@'%' IDENTIFIED BY 'asAS123456!'; # 赋予主从同步权限 GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%'; # 创建一个远程链接用户,这用户用在Navicat、JDBC登录的时候,直接用root不好 create user 'remote'@'%' identified with mysql_native_password by 'asAS123456!'; # 为remote用户赋予权限 grant all privileges on *.* to remote@'%'; FLUSH PRIVILEGES; # 大坑3: # 删除已经产生的binlog # 一定要RESET MASTER,他会删除刚才已经产生的binlog # 因为刚才binlog包含创建这种高权限操作,用于主从同步的rpl_user账户是没有权限执行的 # 这回导致RelayLog重放无法正确执行,导致从属服务器卡死在RECEVERING状态 # 利用RESET MASTER删除这些无法执行的binlog,就没有问题了 RESET MASTER; -
安装MGR插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';安装完成之后可以查看插件是否已经安装完成:
SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'group_replication' \G

-
master服务器上运行以下命令:
SET GLOBAL group_replication_bootstrap_group = ON; START GROUP_REPLICATION; SET GLOBAL group_replication_bootstrap_group = OFF; -
replication服务器上运行以下命令:
CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="asAS123456!" FOR CHANNEL 'group_replication_recovery'; START GROUP_REPLICATION; -
验证是否成功:
SELECT * FROM performance_schema.replication_group_members;

2.2 集群故障排查
- 网络不通

- 事务进度不一致

解决办法:从属服务器停止,Reset binlog,重新同步
STOP GROUP_REPLICATION;
RESET MASTER;
CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="asAS123456!" FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
- 无法执行create user...

3 MGR故障转移实验
选举策略:
- 优先低版本的节点
- 如果版本一样,优先权重大的节点
- 如果版本与权重一样的,按照server uuid的字母顺序选主
-
既有的集群:
可以看到n2的member uuid比n1小,所以按理来说n0关闭之后,n2将成为新的主节点

- 将n0关闭,查新新的集群信息:

并且查看n2节点的log可以看到以下内容:
# 将n0从group中移除,重新选主
2022-03-19T14:50:19.619327Z 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: n0:3306'
2022-03-19T14:50:19.619347Z 0 [System] [MY-011500] [Repl] Plugin group_replication reported: 'Primary server with address n0:3306 left the group. Electing new Primary.'
# n2节点被选举为新的主,执行之前未完成的事务处理
2022-03-19T14:50:19.619424Z 0 [System] [MY-011507] [Repl] Plugin group_replication reported: 'A new primary with address n2:3306 was elected. The new primary will execute all previous group transactions before allowing writes.'
# 当前group成员变更为n1、n2
2022-03-19T14:50:19.619565Z 0 [System] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to n2:3306, n1:3306 on view 16476998177917418:6.'
# 关闭n2节点的只读状态,设置super_read_only=OFF
2022-03-19T14:50:19.620327Z 19 [System] [MY-013731] [Repl] Plugin group_replication reported: 'The member action "mysql_disable_super_read_only_if_primary" for event "AFTER_PRIMARY_ELECTION" with priority "1" will be run.'
2022-03-19T14:50:19.620443Z 19 [System] [MY-011566] [Repl] Plugin group_replication reported: 'Setting super_read_only=OFF.'
# 自动启用故障转移
2022-03-19T14:50:19.620471Z 19 [System] [MY-013731] [Repl] Plugin group_replication reported: 'The member action "mysql_start_failover_channels_if_primary" for event "AFTER_PRIMARY_ELECTION" with priority "10" will be run.'
# n2节点作为主节点开始工作
2022-03-19T14:50:19.620906Z 40 [System] [MY-011510] [Repl] Plugin group_replication reported: 'This server is working as primary member.'
n1节点可以看到以下log:
# 将n0从group中移除,重新选主
2022-03-19T14:50:19.619733Z 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: n0:3306'
2022-03-19T14:50:19.619765Z 0 [System] [MY-011500] [Repl] Plugin group_replication reported: 'Primary server with address n0:3306 left the group. Electing new Primary.'
# n2节点被选举为新的主,执行之前未完成的事务处理
2022-03-19T14:50:19.619804Z 0 [System] [MY-011507] [Repl] Plugin group_replication reported: 'A new primary with address n2:3306 was elected. The new primary will execute all previous group transactions before allowing writes.'
# 当前group成员变更为n1、n2
2022-03-19T14:50:19.619984Z 0 [System] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to n2:3306, n1:3306 on view 16476998177917418:6.'
# n1节点作为n2节点的从节点开始工作
2022-03-19T14:50:19.620549Z 34 [System] [MY-011511] [Repl] Plugin group_replication reported: 'This server is working as secondary member with primary member address n2:3306.'
如果继续将n2也下线的话,会发现尽管n2已经下线,但是n1查看集群状态时还显示在,是因为只有1个节点的情况下,少于n/2+1的规则,导致整体MGR集群失效,n1节点无法重新选举,同时n1的日志也不会有任何新的内容。
整体回复集群
按照n1,n2,n0的顺序重新加入MGR集群,重新运行以下命令:
START GROUP_REPLICATION;
4 单主模式与多主模式
在单主模式下,组复制具有自动选主功能,每次只有一个server成员接受更新。单写模式group内只有一台节点可写可读,其他节点只可以读。对于group的部署,需要先跑起prmary节点,然后再跑起其他的节点,并把这些点加进group。其他的节点就会自动同步primary节点上面的变化,然后将自己设置为只读模式。当primary节点意外宕机或者下线,在满足大多数节点存活的情况下,group内部发起选举,选出下一个可用的读节点,提升为primary
节点。primary选举根据group内剩下存活节点的UUID按字典序升序来选择,然后选择排在最前的节点作为新的primary节点。
在多主模式下,所有的 server 成员都可以同时接受更新。group内的所有机器都是primary节点,同时可以进行读写操作,并且数据是最终一致的。
单主模式

多主模式

4.1 运行时切换为多主模式
- n0~n2节点停止组复制,并开启多主模式
stop group_replication;
# 是否启用多主模式,默认ON,OFF代表多主
set global group_replication_single_primary_mode=OFF;
# 是否开启条件检查,因为多主的约束更加严格,不符合要求的直接拒绝
# 不支持外键的级联操作
# 不支持“串行化Serializable”
set global group_replication_enforce_update_everywhere_checks=ON;
- n0节点引导启动组复制
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group = OFF;
- n1,n2启用组复制,加入MGR集群
START GROUP_REPLICATION;
可以看到所有的节点都编程了primary节点

4.2 运行时切回单主模式
- 所有节点停止组复制,切回单主模式
stop group_replication;
set global group_replication_enforce_update_everywhere_checks=OFF;
set global group_replication_single_primary_mode=ON;
- 其他的一样
在设计上可以和应用层结合起来,有两种部署模式:分别为应用层双活和数据库双活,应用层双活和数据库单活
- MGR集群多活架构
基于MGR的多活特性,数据的写入可以在多个节点之间复制,实现数据的强一致性需求,并且在节点通信出现延迟的情况下,会自动实现服务降级。对于此类方案,我们可以采用同机房多写,同城异机房只读的方案。

- 双主模式的多活
两个节点均可以写入数据,可以实现跨机房的数据复制,延迟较低,在业务层需要做隔离,在故障发生时能够快速切换到同机房的Slave节点。此方案对于两个IDC机房的场景中较为实用,但是机房多活的场景不适合。

- 业务交叉的双活方案
5 ProxySQL






评论区