【MySQL】MySQL高可用集群之组复制(MGR)--多主模式搭建,单主--多主模式转换

前情提要:本篇博客参考mysql官方文档详细介绍了MGR的原理,特点,单主/多主模式,并且详细讲解了MGR集群搭建部署,模式切换还有故障恢复的全部流程,通过本篇博客你可以学会MGR的原理还有上述全部的实验配置。

一、MGR简介

1.1 什么是MGR

  • MySQL Group Replication(简称 MGR )是 MySQL 官方于 2016 年 12 月推出的一个全新的高可用与高扩展的解决方案,是MySQL自带的一个插件
  • 组复制是 MySQL 5.7.17 版本出现的新特性,它提供了高可用、高扩展、高可靠的 MySQL 集群服务
  • MySQL 组复制分单主模式和多主模式,传统的 mysql 复制技术仅解决了数据同步的问题,
  • MGR 对属于同一组的服务器自动进行协调。对于要提交的事务,组成员必须就全局事务序列中给定事务的顺序达成一致
  • 提交或回滚事务由每个服务器单独完成,但所有服务器都必须做出相同的决定
  • 如果存在网络分区,导致成员无法达成事先定义的分割策略,则在解决此问题之前系统不会继续进行,这是一种内置的自动裂脑保护机制
  • MGR 由组通信系统(Group Communication System,GCS ) 协议支持
  • 该系统提供故障检测机制、组成员服务以及安全且有序的消息传递

  • 保证数据一致性又可以自动切换,具备故障检测功能、支持多节点写入。

  • 集群是多个MySQL Server节点共同组成的分布式集群,每个Server都有完整的副本,它是基于ROW格式的二进制日志文件和GTID特性。

1.2 MGR的特点

  • 强一致性:基于原生复制及paxos协议的组复制技术,并以插件的方式提供,提供一致数据安全保证。

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

  • 高扩展性:节点的新增和移除都是自动的,新节点加入后,会自动从其他节点上同步状态,直到新节点和其他节点保持一致,如果某节点被移除了,其他节点自动更新组信息,自动维护新的组信息。

  • 高灵活性:有单主模式和多主模式。单主模式下,会自动选主,所有更新操作都在主上进行;多主模式下,所有server都可以同时处理更新操作。

  • 仅支持InnoDB表,并且每张表一定要有一个主键,用于做write set的冲突检测。

  • 必须打开GTID特性,二进制日志格式必须设置为ROW,用于选主与write set;主从状态信息存于表中(--master-info-repository=TABLE 、--relay-log-inforepository=TABLE),--log-slave-updates打开。

  • MGR不支持大事务,事务大小最好不超过143MB,当事务过大,无法在5秒的时间内通过网络在组成员之间复制消息,则可能会怀疑成员失败了,然后将其驱逐出局。

  • 目前一个MGR集群最多支持9个节点。

  • 不支持外键于save point特性,无法做全局间的约束检测与部分事务回滚。

  • 二进制日志不支持Binlog Event Checksum。

1.3 组复制流程

首先我们将多个节点共同组成一个复制组,在执行读写(RW)事务的时候,需要通过一致性协议层(Consensus 层)的同意,也就是读写事务想要进行提交,必须要经过组里"大多数人"(对应 Node 节点)的同意,大多数指的是同意的节点数量需要大于 (N/2+1),这样才可以进行提交,而不是原发起方一个说了算。而针对只读(RO)事务则不需要经过组内同意,直接 提交 即可

1.4 单主模式/多主模式简介

1.4.1 单主模式

在单主模式下(group_replication_single_primary_mode=ON),组内有一个主服务器设置为读/写模式,其余所有成员均设置为只读模式(super_read_only=ON)。主服务器通常负责引导整个组。加入组的其他服务器会自动识别主服务器,并设置为只读模式。

在单主模式下,组复制强制规定仅允许单个服务器执行写操作,因此与多主模式相比,其一致性检查可相对宽松,且无需对DDL语句进行额外处理。系统变量 group_replication_enforce_update_everywhere_checks 用于启用或禁用组内的严格一致性检查。在部署单主模式或切换至单主模式时,必须将该变量设置为 OFF。

主服务器的变更可通过以下方式实现:

  • 当现有主服务器(无论主动或意外)离开组时,系统会自动选举新的主服务器。

  • 可使用 group_replication_set_as_primary() 函数指定特定成员作为新主服务器。

  • 若通过 group_replication_switch_to_single_primary_mode() 函数将运行在多主模式的组切换为单主模式,系统会自动选举新主服务器,也可通过该函数参数指定新主服务器。

注意:上述功能仅在所有组成员运行 MySQL 8.0.13 或更高版本时可用。

当新主服务器被选举(自动或手动)产生后,其将自动设置为读/写模式,其余组成员则保持为只读的从服务器状态。下图展示了该过程:

注意:以上单主模式文字和图片内容均参考了mysql官方文档: https://dev.mysql.com/doc/refman/8.0/en/group-replication-single-primary-mode.html

1.4.2 多主模式

在多主模式下(group_replication_single_primary_mode=OFF),所有成员均无特殊角色差异。任何与其他组成员兼容的服务器在加入组时,均被设置为读/写模式,并且能够处理写入事务,即使这些事务是并发执行的。

如果某个成员停止接受写入事务(例如因服务器意外退出),连接到该成员的客户端可被重定向或故障转移到其他处于读/写模式的成员。组复制本身不处理客户端故障转移,因此需要通过中间件框架(如 MySQL Router 8.0)、代理、连接器或应用程序自身来实现该功能。

注意:以上多主模式文字和图片内容均参考了mysql官方文档: https://dev.mysql.com/doc/refman/8.0/en/group-replication-multi-primary-mode.html

二、MGR集群搭建

2.1 MGR环境部署

环境清单

Linux系统:RHEL9.3

mysql版本:mysql Ver 8.3.0 for Linux on x86_64 (Source distribution)

主机名 IP
mysql-node1 172.25.254.10
mysql-node2 172.25.254.20
mysql-node3 172.25.254.30

2.2 MGR多主模式搭建

2.2.1 准备三台数据库主机

将三台数据库初始化,保证实验环境纯净

1、配置本地解析文件,组复制要求三台主机互相可以解析

cpp 复制代码
# 在所有节点配置/etc/hosts文件
[root@mysql-node1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.10     mysql-node1
172.25.254.20     mysql-node2
172.25.254.30     mysql-node3

2、关闭mysql服务并删除数据文件

cpp 复制代码
# 三台主机均做此操作
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
[root@mysql-node1 ~]# rm -rf /data/mysql/*

3、修改/etc/my.cnf配置文件并初始化mysql

开始编写/etc/my.cnf配置文件 (配置内容参考了官方文档)

cpp 复制代码
# 三台主机均做此操作
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql		# 数据存储目录
socket=/data/mysql/mysql.sock	# 本地客户端通过此文件连接数据库,避免网络开销
symbolic-links=0	# 禁用符号链接,防止如果软链接访问或移动数据文件,提高安全性

#不同主机server-id一定要根据实际情况做相应改变
server-id=10|20|30	# 也是数据库在集群中的唯一标识
log-bin=mysql-bin	# 启用二进制日志,是所有复制的基础

gtid_mode=ON	# 启用全局事务标识(GTID),为每个事务分配全局唯一ID,简化复制和故障恢复。
enforce-gtid-consistency=ON		# 强制gtid一致性,确保事务安全基于gtid复制
default_authentication_plugin=mysql_native_password		# 设置默认身份验证插件为传统模式,避免身份认证影响数据同步
log_slave_updates=ON	# 从库将接收到的更新写入自己的binlog,确保事务再集群内持续同步
binlog_format=ROW	# binlog记录格式为"行模式",记录数据行的实际变更(而非SQL语句),保证数据一致性,是组复制的推荐格式
binlog_checksum=NONE	# 禁用binlog校验和。某些组复制场景下为兼容性可能需要关闭。
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"	# 禁用不支持事务或不适合组复制的存储引擎,强制使用 InnoDB(组复制要求事务型存储引擎)

# 官方8.0文档还有三个参数,上面没有写,在此处做出解释
# master_info_repository=TABLE
# relay_log_info_repository=TABLE
# transaction_write_set_extraction=XXHASH64
# 在MySQL8.0+中,以上前两个参数已成为默认值
# 在MySQL8.0+中,如果启用了binlog和gtid,则第三个为默认值

4、以上配置文件写好后初始化数据库

cpp 复制代码
# 三台数据库均要初始化
[root@mysql-node1 ~]# mysqld --user=mysql --initialize

2.2.2 部署组复制

1、完成初始化后编辑配置文件配置组复制并启动mysql

添加以下内容到/etc/my.cnf

cpp 复制代码
# 在所有主机中添加以下内容
[root@mysql-node1 ~]# vim /etc/my.cnf
plugin_load_add='group_replication.so'	# 在MySQL启动时自动加载Group Replication插件
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"		# 指定组复制集群的名称,必须是一个有效的UUID格式字符串
group_replication_start_on_boot=off		# 控制MySQL服务启动时是否自动启动组复制。
group_replication_local_address="172.25.254.10:33061"   #其他两台主机一定要根据ip进行修改,指定当前节点用于组内成员通信的地址和端口
group_replication_group_seeds="172.25.254.10:33061,172.25.254.20:33061,172.25.254.30:33061"		# 指定组复制集群中种子成员的地址列表,用于新节点加入集群时发现集群
group_replication_bootstrap_group=off	# 指定是否引导组复制集群,即初始化一个新的集群
group_replication_single_primary_mode=OFF	# 指定组复制运行模式是否为单主模式,此处为启用多主模式

[root@mysql-node1 ~]# /etc/init.d/mysqld start    # 配置完成后启动mysql

2、配置文件编辑完后开启mysqld并且进行组复制配置

在第一台主机中做如下配置:

cpp 复制代码
[root@mysql-node1 ~]# mysql -uroot -p'lsyVh+etR1ht'
mysql> alter user root@localhost identified   by '123';
Query OK, 0 rows affected (0.04 sec)

mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE USER rpl_user@'%' IDENTIFIED BY '123';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT CONNECTION_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql>  GRANT GROUP_REPLICATION_STREAM ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user', SOURCE_PASSWORD='123' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> SHOW PLUGINS;     #查看组复制插件是否激活
| group_replication               | ACTIVE   | GROUP REPLICATION  | group_replication.so | GPL     |
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='123';
Query OK, 0 rows affected (1.10 sec)

mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier | ac3d6eaf-1a0a-11f1-9efa-000c29f4a60c | mysql-node1 |        3306 | ONLINE       | PRIMARY     | 8.3.0          | XCom                       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
1 row in set (0.00 sec)

3、配置剩余主机加入组群中,操作与第一台类似

cpp 复制代码
[root@mysql-node2 ~]# /etc/init.d/mysqld start
[root@mysql-node2 ~]# mysql -uroot -p'XkP<Uaa:9so5'
mysql> alter user root@localhost identified   by '123';
Query OK, 0 rows affected (0.00 sec)

mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE USER rpl_user@'%' IDENTIFIED BY '123';
Query OK, 0 rows affected (0.00 sec)

mysql>  GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT CONNECTION_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT GROUP_REPLICATION_STREAM ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql>  SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)

mysql>  CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user',SOURCE_PASSWORD='123' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='123';
ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log.			#出现此处报错可以初始化下master

# 产生该错误的主要原因:alter user操作是在SET SQL_LOG_BIN=0之前执行的!所以该操作被记录到了binlog中,并且被分配了一个gtid,所以该节点与主节点gtid集合不一致,导致错误

mysql> reset master;			#用过此命令解决以上报错
Query OK, 0 rows affected, 1 warning (0.04 sec)

# 该命令会重置gtid执行历史,执行后该节点的gtid集合变为空,与主节点一致。

mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='123';
Query OK, 0 rows affected (7.94 sec)

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier | ac3d6eaf-1a0a-11f1-9efa-000c29f4a60c | mysql-node1 |        3306 | ONLINE       | PRIMARY     | 8.3.0          | XCom                       |
| group_replication_applier | e0b37b20-1a0b-11f1-a62c-000c29e84b64 | mysql-node2 |        3306 | ONLINE       | PRIMARY     | 8.3.0          | XCom                       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
2 rows in set (0.00 sec)

#看到主机online表示成功

2.2.3 测试

1、在node1创建数据库和表并插入数据

cpp 复制代码
mysql> create database MGR_test;
Query OK, 1 row affected (0.01 sec)

mysql> use MGR_test;
Database changed
mysql> create table test1(a varchar(10)primary key,b varchar(10));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test1 values('a','1');
Query OK, 1 row affected (0.01 sec)

mysql> select * from MGR_test.test1;
+---+------+
| a | b    |
+---+------+
| a | 1    |
+---+------+
1 row in set (0.00 sec)

2、在node2和node3直接查询该表

cpp 复制代码
# node2
mysql> select * from MGR_test.test1;
+---+------+
| a | b    |
+---+------+
| a | 1    |
+---+------+
1 row in set (0.00 sec)

# node3
mysql> select * from MGR_test.test1;
+---+------+
| a | b    |
+---+------+
| a | 1    |
+---+------+
1 row in set (0.00 sec)

至此MGR多主模式搭建完毕

2.3 MGR的模式切换

2.3.1 多主---->单主

前面搭建为多主模式,要改为单主模式,需要进行以下操作

1、在所有节点上停止复制,开启单主模式

cpp 复制代码
mysql> stop group_replication;
mysql> set global group_replication_enforce_update_everywhere_checks=OFF;
mysql> set global group_replication_single_primary_mode=ON;

2、在node1主节点启用组复制

cpp 复制代码
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;

3、在node2和node3从节点启用组复制

cpp 复制代码
mysql> START GROUP_REPLICATION;

4、此时,可以看到三台MySQL变成了主从模式:

cpp 复制代码
mysql> SELECT * FROM performance_schema.replication_group_members;

2.3.2 单主---->多主

1、所有节点停止组复制,开启多主模式

cpp 复制代码
mysql> stop group_replication;
mysql> set global group_replication_single_primary_mode=OFF;
mysql> set global group_replication_enforce_update_everywhere_checks=ON;

2、在node1主节点启用组复制

cpp 复制代码
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;

3、在node2与node3启用组复制

cpp 复制代码
mysql> START GROUP_REPLICATION;

4、此时,可以看到三台MySQL都是主节点:

cpp 复制代码
mysql> SELECT * FROM performance_schema.replication_group_members;

三、MGR故障恢复

3.1 模拟node1故障下线

使用单主模式进行实验

当前集群主从关系如下:

1、在node1停止mysql

cpp 复制代码
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
Shutting down MySQL....... SUCCESS!

2、查看从节点node2

cpp 复制代码
mysql> SELECT * FROM performance_schema.replication_group_members;

可见node2被选为主节点

3、查看node2日志

cpp 复制代码
[root@mysql-node2 ~]# tail -n 20 /data/mysql/mysql-node2.err

# node1被移除出组
2026-03-09T02:39:34.017185Z 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: mysql-node1:3306'

# 重新开始选举新主节点
2026-03-09T02:39:34.017225Z 0 [System] [MY-011500] [Repl] Plugin group_replication reported: 'Primary server with address mysql-node1:3306 left the group. Electing new Primary.'

# 选中node2为新主节点并执行之前未完成的事务
2026-03-09T02:39:34.017377Z 0 [System] [MY-011507] [Repl] Plugin group_replication reported: 'A new primary with address mysql-node2:3306 was elected. The new primary will execute all previous group transactions before allowing writes.'

# 组成员只剩node2,node3
2026-03-09T02:39:34.017561Z 0 [System] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to mysql-node2:3306, mysql-node3:3306 on view 17730238840447259:4.'

# node2 在当选后,首先将自己设置为 super_read_only=ON(只读)。这是一个中间安全状态。
2026-03-09T02:39:34.018300Z 42 [System] [MY-011565] [Repl] Plugin group_replication reported: 'Setting super_read_only=ON.'

# 触发名为 mysql_disable_super_read_only_if_primary的成员动作,其优先级为1。
2026-03-09T02:39:34.018892Z 31 [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.'

# 执行上述动作,将 super_read_only设置为 OFF。至此,node2 正式成为可读写的活跃主节点。
2026-03-09T02:39:34.018957Z 31 [System] [MY-011566] [Repl] Plugin group_replication reported: 'Setting super_read_only=OFF.'

# 触发另一个优先级为10的成员动作 mysql_start_failover_channels_if_primary,这通常用于配置故障转移通道等后续任务。
2026-03-09T02:39:34.019064Z 31 [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.'

# node2 确认自己已作为主成员正常运行。
2026-03-09T02:39:34.019707Z 42 [System] [MY-011510] [Repl] Plugin group_replication reported: 'This server is working as primary member.'

3.2 恢复node1

1、node1重启mysql服务

cpp 复制代码
[root@mysql-node1 ~]# /etc/init.d/mysqld restart

2、node1执行以下命令即可恢复

cpp 复制代码
mysql> CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user',SOURCE_PASSWORD='123' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='123';
Query OK, 0 rows affected (1.63 sec)

mysql> SELECT * FROM performance_schema.replication_group_members;

3、通过测试,当某节点故障后,其余节点产生了新事物,待该节点恢复也可以正常同步

cpp 复制代码
# 在该节点故障时其余节点插入了该表第二行数据
mysql> select * from MGR_test.test1
    -> ;
+---+------+
| a | b    |
+---+------+
| a | 1    |
| b | 2    |
+---+------+
2 rows in set (0.00 sec)
# 在同步后可见该节点也自动同步

至此,MGR集群搭建与故障恢复实验完成

相关推荐
怀旧诚子16 分钟前
timeshift之Fedora43设置,已在VM虚拟机验证,待真机验证。
java·服务器·数据库
haixingtianxinghai1 小时前
Redis的定期删除和惰性删除
数据库·redis·缓存
资深web全栈开发1 小时前
PostgreSQL Schema 最佳实践:架构师的命名与组织艺术
数据库·postgresql
sdm0704272 小时前
yum和开发工具vim/gcc
linux·服务器·centos
麦聪聊数据2 小时前
利用实时数据管道与 SQL2API 重构企业自动化审计架构
数据库·sql·低代码
麦聪聊数据2 小时前
重构开放生态:利用 QuickAPI 跨越遗留系统与敏捷交付的工程实践
数据库·sql·低代码·restful
百结2147 小时前
Mysql数据库操作
数据库·mysql·oracle
keep one's resolveY7 小时前
时区问题解决
数据库
Leinwin7 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
2401_865382508 小时前
信息化项目运维与运营的区别
运维·运营·信息化项目·政务信息化