MySQL 8.0.36 实战:主从复制 · GTID · 半同步 · 组复制
关键词:MySQL 8.0.36 / 主从复制 / GTID / 半同步复制 / 组复制 MGR
本文基于 MySQL 8.0.36,在三节点环境下从零开始,按难度递进依次搭建四种复制架构,
最终完成组复制(MGR)。每一步都有完整配置与验证命令,可直接照做。
目录
前言
环境规划
传统主从复制(基于 binlog 文件 + 位点)
升级为 GTID 模式
开启半同步复制
组复制(MGR)
四种复制方式对比
1. 前言
MySQL复制(Replication)是实现数据库多实例同步的核心方案,广泛用于读写分离、数据备份、故障容灾,异地多活等场景,传统主从采用主库推送变更日志,从库放回日志的思路实现数据同步。
整体工作流程,主库(MASTER)执行增删改与DDL操作,事务提交时将数据变更事件记录到二进制日binlog。从库启动IO线程,使用复制用户主动连接主库请求binlog;主库通过Binlog Dump线程持续推送日志事件,从库的IO线程接收后写入本地中继日志relay log。随后从库的SQL线程读取中继日志,串行或并行的执行日志内的事件,在本地复现主库的数据修改,最终实现主从数据一致。
MYSQL的三种复制模式:
- 异步复制(默认):主库写入binlog后直接响应客户端,不会等待从接收日志。优势是性能高,风险为主库宕机时,未同步到从库的日志可能会丢失。
- 半同步复制:以插件形式开启,主库提交事务后,需要等待至少一台从库接收binlog成功并写入中继日志,才向客户端返回执行结果,用户甚至可以设置死等。若从库响应超时,会自动降级为异步复制,兼顾性能和数据安全。
- 组复制 MGR使用独立的XCom Paxos协议,区别于传统一主多从架构,支持多节点并发写入,内置冲突检测、自动选主,故障隔离,是MYSQL原生高可用方案。
MGR组复制具有单主模式和多主模式,节点间相互通信,消息组内广播,独立的XCom(33061)端口完成集群内协商通信,网络开销更高,对网络稳定性要求严苛;多主模式下多节点同时写入同一行,会检测冲突并回滚失败业务。
本博客按照真实学习路径,从最简单的主从复制起步,一步步进化到组复制:
传统主从(文件+位点) → GTID 模式 → 半同步 → 组复制 MGR ① ② ③ ④每一步都在上一节的基础上叠加,配置可平滑升级,不需要从头重搭。
前置知识:掌握基本 SQL 与 MySQL 日常运维(启动/停止、配置文件、查看日志);
了解 InnoDB 引擎与 binlog 的概念更佳。本文不展开 MySQL 安装细节(tar 包解压、初始化、
systemd 管理),只聚焦复制架构本身。
2. 环境规划
centos7系统三台节点,同局域网,/etc/hosts已互相解析(强烈建议配置,避免主机名解析问题):
| 节点 | 主机名 | IP | 第一阶段角色 | 最终角色 |
|---|---|---|---|---|
| node1 | server1 | 192.168.40.131 | Master(主库) | 组复制成员 1 |
| ndoe2 | server2 | 192.168.40.132 | Slave1(从库) | 组复制成员 2 |
| node3 | server3 | 192.168.40.133 | Slave2(从库) | 组复制成员 3 |
规划说明:
- MySQL 版本统一为8.0.36(Linux 二进制或 tar 包安装均可,本文用 systemd 管理)本文的程序的默认路径
/usr/local/mysql,并且添加到环境变量,并且配置文件的存放位置统一为/etc/mysql/my.cnf。 - 主从复制使用
3306;组复制额外使用33061作为成员内部通信端口
(group_replication_local_address)。 - 复制账号统一用
repl,密码示例repl,生产环境请替换为强密码。 - 每台节点上都创建mysql用户,确保ID一致。本文中UID与GIID均为1002。
groupadd-g1002mysql#指定创建GID为1002的mysql组useradd-u1002-gmysql-M-d/usr/local/mysql/-s/sbin/nologin mysql#指定mysql用户家目录idmysqluid=1002(mysql)gid=1002(mysql)groups=1002(mysql)严格执行生产环境中程序盘和数据盘分离原则,数据盘位于
/data/mysql下。确保每台节点的地址解析,所有主机添加hosts解析。
环境相关的三个易漏项:
- 时间同步:组复制成员间的消息带时间戳,时钟偏差过大会影响事务排序与日志一致性,
三台节点务必启用chrony或ntp保持时钟一致(timedatectl set-ntp true)。 - 防火墙 / SELinux:放通
3306(SQL 连接)与33061(组复制内部通信)两个端口;
若开启 SELinux 还需放行 mysqld 相应端口,否则复制/组通信会莫名失败。 - 账号安全:复制账号
repl建议限定来源网段(如'repl'@'192.168.40.%')并使用强密码,
避免弱口令账号裸露在整个网段内。
3. 传统主从复制(基于 binlog 文件 + 位点)
3.1 原理
主从复制核心是binlog:
Master Slave 事务提交 ──> binlog ──拉取──> IO_Thread 写入本地 relay_log └─> SQL_Thread 重放到自身库- Binlog Dump 线程(主库侧):主库为每个从库连接维护一个 dump 线程,持续把 binlog
事件推送给从库的 IO 线程;没有从库连接时该线程处于休眠。 - IO_Thread(从库侧):连接主库、拉取 binlog,并顺序写入从库的
relay_log(中继日志)。 - SQL_Thread(从库侧):读取 relay_log,把其中的事务在本地重放一遍,完成数据同步。
- **默认异步:**主库写完binlog就返回客户端,不等待从库接收。
- 传统模式靠文件名 + 位点(File / Position)定位复制到哪了:IO 线程记录"已经拉到哪个
位置",SQL 线程记录"已经执行到哪个位置",两者都由主库的 binlog 文件名 + 偏移量表示。
从库写入 relay_log 的事务并不会自动转存进自己的 binlog——这正是"从库要当主库时必须开
log_slave_updates"的原因,见 3.3 的补充说明。
3.2 主库配置(server1)
以 node1 为例,主库核心配置项(node2/node3 只需把server_id改成 2、3):
[mysqld] server_id = 1 # 全局唯一,所有节点不能重复 log_bin = /data/mysql/binlog/mysql-bin # 开启二进制日志(主库必须) binlog_format = ROW # 8.0 默认即 ROW sync_binlog = 1 # 每提交一个事务就 fsync binlog,防止丢日志 binlog_expire_logs_seconds = 2592000 # binlog 保留 30 天 max_binlog_size = 256M| 参数 | 作用 | 说明 |
|---|---|---|
server_id | 节点唯一标识 | 复制链路上所有节点都不能重复 |
log_bin | 开启二进制日志 | 主库必开;从库按需决定(见 3.3) |
binlog_format | binlog 记录格式 | 8.0 默认 ROW,记录"每一行怎么变",最安全 |
sync_binlog | binlog 落盘策略 | =1每事务同步刷盘,配合innodb_flush_log_at_trx_commit=1可做到主库零丢失 |
binlog_expire_logs_seconds | binlog 保留时长 | 从库掉线太久可能发现所需 binlog 已被清理,需权衡设置 |
binlog_format三种取值的取舍:
- ROW(8.0 默认):记录每行的变更结果,不受
NOW()、UUID()等非确定性函数影响,
恢复最准确,也是组复制 MGR 的硬性要求。- STATEMENT:只记录执行过的 SQL,日志量小,但非确定性函数、触发器可能造成主从不一致。
- MIXED:让 MySQL 自动在两者间切换,行为更难预测,生产环境不推荐。
3.3 从库配置(server2 / server3)
节点内的server-id不能一致,server3上的server-id的值为3,这是从库的配置文件之间唯一的差别。从库可以开启只读功能,防止误读;同时关闭二进制日志功能,以减少性能损失。
"从库要不要开 binlog"再展开一点:
- 单纯做只读/备份的从库,关闭 binlog 确实能省一点 I/O;
- 但若从库未来要级联复制(作为更下游节点的主库),或参与主从切换,则必须
log_bin = ON且log_slave_updates = ON,否则从库的 binlog 里不会包含
“从主库同步来的事务”,下游和接替方就拿不到数据。- 后面的GTID 升级与组复制 MGR都强制要求
log_slave_updates = ON,
建议从库直接一并配上,避免以后再改配置重启。- 从库建议同时加
read_only = ON(超级账号仍可写,防止业务误写从库)与skip_replica_start = ON(重启后不自动复制,便于人工确认后再启动)。
改完配置后三台节点都初始化数据、开启mysql,并通过临时密码登录 MySQL:
在每个节点初始化之前一定要确保/data/mysql/文件夹下为空,否则会出现启动失败,数据不同步等错误。
3.4 创建复制账号
复制账号用于从库登陆主库做身份验证,并且凭借REPLICATN SLAVE权限,让主库开启dump线程,向从库推送binlog日志。
在主库 server1 上执行:
复制账号遵循最小权限原则,只需复制相关权限,不要授予超级权限:
CREATEUSER'repl'@'%'IDENTIFIEDBY'repl';-- 生产请用强密码并限定来源网段GRANTREPLICATIONSLAVE,REPLICATIONCLIENTON*.*TO'repl'@'%';FLUSHPRIVILEGES;REPLICATION SLAVE:允许从库用该账号拉取 binlog(8.0.22+ 也可写作REPLICATION REPLICA)。REPLICATION CLIENT:允许执行SHOW MASTER STATUS等复制状态命令,便于排查,非必需。
由MASTER状态可以看出,从二进制日志文件binlog.000002的偏移位点1299开始从库同步。
3.5 配置从库
⚠️ 若主库已有业务数据,请先
mysqldump --master-data全量备份并恢复到从库,
再执行下面的CHANGE MASTER TO;本文假设数据为空或已处理。
从库上执行:
CHANGE MASTER TO各参数含义(8.0.23+ 官方推荐CHANGE REPLICATION SOURCE TO,二者等价):
| 参数 | 含义 |
|---|---|
MASTER_HOST | 主库 IP,必须能从从库网络访问到 |
MASTER_PORT | 主库端口,默认 3306 |
MASTER_USER/MASTER_PASSWORD | 3.4 创建的复制账号repl |
MASTER_LOG_FILE/MASTER_LOG_POS | 主库SHOW MASTER STATUS给出的文件 + 位点 |
MASTER_AUTO_POSITION | 设为 1 即启用 GTID 自动定位(第 4 节) |
位点从哪来?在主库执行
SHOW MASTER STATUS\G查看File与Position两列。
若主库已有业务数据,用mysqldump --single-transaction --master-data=2导出时,dump 文件
头部会自动携带一条CHANGE MASTER TO ...(--master-data=2是注释形式,人工确认后放开;
若主库已开 GTID 还会附带SET @@GLOBAL.GTID_PURGED=...)。
(8.0.23 开始官方推荐写法为CHANGE REPLICATION SOURCE TO与START REPLICA,
二者等价,下文为可读性沿用MASTER/SLAVE关键字。)
3.6 验证
在SHOW SLAVE STATUS\G输出中确认两个关键项:
读写验证:主库建表插入数据,从库立即能查到:
-- 主库CREATEDATABASEtestdb;CREATETABLEtestdb.t1(idINTPRIMARYKEY,nameVARCHAR(50));INSERTINTOtestdb.t1VALUES(1,'hello');-- 从库SELECT*FROMtestdb.t1;-- 能查到 (1, 'hello') 即成功日常监控命令(从库执行):
SHOWSLAVESTATUS\G| 输出项 | 含义 |
|---|---|
Slave_IO_Running | IO 线程是否连上主库、正常拉取 binlog |
Slave_SQL_Running | SQL 线程是否正常执行 relay log 中的事务 |
Seconds_Behind_Master | 主从延迟秒数(估算值,0 表示已追上) |
Master_Log_File/Read_Master_Log_Pos | IO 线程已拉取到的位置 |
Relay_Master_Log_File/Exec_Master_Log_Pos | SQL 线程已执行到的位置 |
Seconds_Behind_Master是估算值:只有 SQL 线程正在执行时才反映真实延迟,空闲时归零,
只能作参考;精确对账应对比主从的 binlog 位点或 GTID 集合(第 4 节)。
提升从库吞吐(8.0 多线程并行复制,可选):
[mysqld] replica_parallel_workers = 4 # 并行应用线程数(旧名 slave_parallel_workers) replica_parallel_type = LOGICAL_CLOCK # 基于事务时间戳/写集并行,8.0 默认即此值 binlog_transaction_dependency_tracking = WRITESET # 主库为并行复制打标,写集并行效果最好大事务(一次性删除/更新几十万行)在从库重放是最常见的延迟来源,除调大并行度外,
更彻底的办法是业务侧把大事务拆小。
传统模式的局限:从库无法精确回答"主库已经执行到哪个事务",位点信息割裂在
各从库的 relay 日志里,主库 crash 后切换极难找准恢复点。这就是 GTID 要解决的问题。
4. 升级为 GTID 模式
4.1 什么是 GTID
GTID(Global Transaction Identifier,全局事务标识符)格式为:
<server_uuid>:<事务序号> 例如 3a3f0c18-9d7a-11ee-a9c8-005056a02b12:1-10server_uuid是每台实例在初始化时生成的 UUID,保存在数据目录的auto.cnf中,
唯一标识"这个事务诞生于哪台机器"。- 事务序号是本实例生成的单调递增整数,多个连续序号可缩写为区间,如
1-10;
多个来源用逗号连接,形成GTID Set,例如3a3f0c18-...:1-10, b2c9d1f4-...:1-5。
特点:
- 每个事务有全局唯一的编号,由"在哪台机器上生成 + 序号"组成。
- 从库能精确知道"我执行到哪些 GTID",主从数据状态可对比、可追踪。
- 主从切换时无需手动寻找位点,
MASTER_AUTO_POSITION=1自动协商同步点。
4.2 升级步骤(主库、从库都要做)
确保主库上的没有任何创建的库,即没有创建的内容。
随后将以下配置写入三台节点的/etc/my.cnf并重启:
[mysqld] gtid_mode = ON enforce_gtid_consistency = ON4.3 从库切换为 GTID 自动定位
STOP SLAVE;CHANGE MASTERTOMASTER_AUTO_POSITION=1;STARTSLAVE;SHOWSLAVESTATUS\G-- 依然要求 Slave_IO_Running / Slave_SQL_Running = Yes现在不需要再关心File / Position了。验证 GTID 已生效:
SELECT@@GLOBAL.GTID_EXECUTED;主从两台机器上看到的GTID_EXECUTED集合应当一致(或从库是主库的子集)。
4.4 GTID 的价值
- 主库宕机后,选出事务最完整的从库,直接
CHANGE MASTER TO MASTER_AUTO_POSITION=1
即可接管,不再需要翻 binlog 找位点。 - 同一台从库换主(级联切换)非常顺滑。
- 排查数据不一致时,直接对比
GTID_EXECUTED与gtid_purged。
GTID 模式下手动切换示例(主库宕机,提升从库为新主):
-- 在候选从库(如 server2)上,把复制指向新主STOP SLAVE;CHANGE MASTERTOMASTER_HOST='新主IP',MASTER_AUTO_POSITION=1;-- 无需再填位点STARTSLAVE;要点:
- 选哪台从库当新主,可对比各从库的
@@GLOBAL.GTID_EXECUTED,选包含事务最全的那台;- 切换后新主继续生成事务,
server_uuid不变,事务序号自动延续,不会与旧主冲突;- 旧主恢复后若想重新挂回集群,需清空数据重新全量同步——旧主上有新主没有的 GTID 时
直接挂会报ER_GTID_NEXT_TYPE_UNDEFINED_GROUP之类的错误(详见 FAQ)。
5. 开启半同步复制
5.1 为什么需要半同步
传统复制是异步的:主库写完binlog,返回客户端成功,不等待从库接收binlog就返回。
**半同步复制(semi-sync)😗*主库提交事务写入binlog后,至少等待一台从库确认收到binlog事件,才给客户端返回提交成功。
注意:只等从库收到日志,不等从库执行回放事务!
核心流程:
- 主库执行事务,写入binlog;
- 主库等待从库回复:已收到binlog日志;
- 收到ACK确认->返回客户端事务成功;
- 超时没收到从库ACK,自动降级为异步复制(保证业务不卡死)。
5.2 安装插件(8.0.26+ 新命名)
8.0.26 起插件名由 master/slave 改为 source/replica,老名字仍作别名可用:
** 主库 **
** 在主库查看半同步的配置状态及参数 **
** 从库 **
用状态变量确认半同步是否真正生效:
SHOWSTATUSLIKE'Rpl_semi_sync%';| 状态变量 | 含义 |
|---|---|
Rpl_semi_sync_source_status | 主库半同步是否处于 ON(1=生效中) |
Rpl_semi_sync_source_clients | 当前处于半同步连接的从库数量 |
Rpl_semi_sync_source_yes_tx | 已收到从库 ACK 的事务数 |
Rpl_semi_sync_source_no_tx | 因超时降级、未收到 ACK 的事务数 |
Rpl_semi_sync_replica_status | 从库半同步是否 ON |
只要
yes_tx在增长,说明链路是真正半同步;若no_tx持续增长,说明在频繁降级为异步,
应排查网络 RTT 与rpl_semi_sync_source_timeout的设置是否过小。
5.3 配置参数(写入 my.cnf 以便持久化)
# node1(主库) [mysqld] plugin_load_add = "rpl_semi_sync_source.so" rpl_semi_sync_source_enabled = 1 rpl_semi_sync_source_timeout = 1000 # 单位 ms(8.0.26+),超时后降级异步 rpl_semi_sync_source_wait_for_replica_count = 1 rpl_semi_sync_source_wait_point = AFTER_SYNC # node2 / node3(从库) [mysqld] plugin_load_add = "rpl_semi_sync_replica.so" rpl_semi_sync_replica_enabled = 1
rpl_semi_sync_source_timeout的行为:主库提交事务后最多等待这么久收 ACK,超时就把
当前事务按异步放行,并临时降级为异步(无需人工复位,从库恢复 ACK 后自动回到半同步)。
权衡:timeout设大 → 更不容易丢事务,但主库故障时阻塞窗口更大;设小 → 主库更稳,
但更容易频繁降级。生产常见取值 1000~5000ms。
5.4 超时降级验证
把一个从库停掉 IO 线程(模拟无 ACK)
STOP SLAVE IO_THREAD;,在主库设置必须接收至少两个从库ACKSET GLOBAL rpl_semi_sync_master_wait_for_slave_count=2,主库写入新数据后观察状态:
(降级为异步期间主库照常工作,不会阻塞业务;等从库恢复后自动回到半同步。)
半同步的局限:主库与从库仍是"一个主、多个从"的星型拓扑,主库是单点;
没有自动选主能力,故障切换仍需手动或借助中间件。组复制在此基础上实现了
自动选举 + 多数派确认。
6. 组复制(MGR)
6.1 组复制是什么
组复制(Group Replication)是 MySQL 官方的高可用方案,核心是XCOM Paxos 共识:
- 成员之间通过
group_replication_local_address(如 33061)互相通信。 - 多数派(quorum)机制:只有超过半数的成员确认某个事务,事务才算提交。
因此 3 节点组可容忍 1 台宕机,5 节点可容忍 2 台。 - 自动选主:单主模式下主库宕机,组内自动选举出新的主,无需人工干预。
- 支持单主(默认)与多主(所有成员都可写)两种模式。
它和普通主从复制在"内部结构"上的差别:
普通复制:1 条 binlog 单向流,从库只有 IO / SQL 两个线程 组复制:每个成员"既是主也是从"——各自保留 binlog,通过 group_replication_applier 通道接收并应用组内广播的事务- 成员收到事务后先做Certification(认证 / 冲突检测):把事务涉及的写集(write set)
与组内其他未决事务比对。写集由transaction_write_set_extraction = XXHASH64生成,
这正是 6.3 前置条件里必须开启它的原因。 - 认证通过的事务才会被 apply 并写进本机 binlog;认证冲突的会被回滚(多主模式见 6.11)。
┌────────────────────┐ │ 组内成员 (Paxos) │ node1 node2 node3 │ │ │ │ │ │ 33061 内网通信 └────────────────────┘6.2 与主从复制的本质区别
| 对比项 | 主从复制 | 组复制 |
|---|---|---|
| 数据同步方式 | binlog 单向拉取 | 事务在成员间广播 + 多数派确认 |
| 主库 | 固定一个 | 单主模式自动选举 / 多主全可写 |
| 故障转移 | 手动 | 自动 |
| 数据一致性 | 异步(或半同步降级) | 强一致(多数派 ACK) |
| 节点加入 | 手动指定位点/GTID | 分布式恢复自动追赶 |
6.3 前置条件(必须全部满足)
组复制对配置有硬性要求,缺一项START GROUP_REPLICATION就会失败:
gtid_mode = ON、enforce_gtid_consistency = ONbinlog_format = ROWlog_slave_updates = ONtransaction_write_set_extraction = XXHASH64disabled_storage_engines排除非 InnoDB 引擎server-id唯一
将数据目录清空,重新初始化数据,防止组间数据开始同步前就不一致
几个容易踩坑的配置细节:
group_replication_local_address的端口(33061)不要复用SQL 端口(3306),两者职责不同。- 每张业务表必须有主键(原因见 6.11),否则 MGR 会拒绝写入。
- 每个节点的复制账号和密码必须一致,否则新节点加入时很可能在已有的节点中同步不到数据。
- 防火墙放通
3306与33061,并确认 SELinux 不拦截 mysqld 的网络访问。
6.4 关键:为什么要"分两次启动"(重点)
在搭建组复制时,第一次用基础配置启动,第二次再补上组复制配置。
原因有四个,任何一个都会让"一次全配"失败:
group_replication_start_on_boot默认是 ON。
一旦plugin_load_add加载了插件,它就会在启动时尝试自动启动组复制。而此刻
数据目录刚初始化、恢复账号还没建、组还不存在 → 直接报错:[ERROR] Plugin group_replication reported: 'The group name option is mandatory'
或'Unable to start Group Replication on boot'。所以配置期必须显式group_replication_start_on_boot = OFF。group_replication_bootstrap_group绝不能写进配置文件。
官方文档明确警告:若把bootstrap_group=ON写进 my.cnf,每次重启都会自动
引导出一个同名新组,制造出两个互相独立的组(脑裂)。引导必须只在运行时、
只由第一个成员、只执行一次。恢复通道账号必须手工创建。
节点间分布式恢复依赖group_replication_recovery通道的复制账号,而账号只能用
SQL 在建好的实例上创建——这就要求实例先能正常启动一次。插件加载需要重启。
plugin_load_add只在启动时生效,天然把流程拆成"先启动建账号 → 重启加载插件"。
正确流程(本章全程按此执行):
第 1 次启动:基础配置(无任何 group_replication_* 项) → 建恢复账号 → 停机 第 2 次启动:追加组复制配置(加载插件、start_on_boot=OFF) → 运行时引导/加入6.5 第一次启动:基础配置
启动并进入 MySQL,创建组复制恢复账号(三台节点都要做,账号密码一致):
账号需要
BACKUP_ADMIN:8.0 组复制做分布式恢复时可能用到 clone 插件,
没有该权限节点会卡在 RECOVERING。
每个节点的复制账号和密码必须一致,否则新节点加入时可能会数据拉取失败。
之后 退出 进入第二次配置。
6.6 第二次启动:追加组复制配置
在/etc/my.cnf追加(node1 示例):
配置说明:
| 参数 | 作用 |
|---|---|
plugin_load_add | 启动时加载组复制插件 |
group_replication_group_name | 组名,必须是合法 UUID,全组一致 |
group_replication_start_on_boot | 配置期必须 OFF,成功后可按需改 ON |
group_replication_local_address | 本节点内部通信地址(33061) |
group_replication_group_seeds | 组内全部成员的种子地址 |
group_replication_bootstrap_group | 引导开关,保持 OFF,运行时临时开 |
group_replication_single_primary_mode | ON=单主模式(默认) |
node2 / node3 追加同样内容,仅将local_address改成各自 IP和各自的server-id。
三台节点依次systemctl restart mysqld启动。
6.7 引导第一个成员(node1)
SETGLOBALgroup_replication_bootstrap_group=ON;-- 只此一次!STARTGROUP_REPLICATION;SETGLOBALgroup_replication_bootstrap_group=OFF;-- 立刻关掉查看成员状态:期望看到 server1 为ONLINE:
6.8 加入其余成员(node2 / node3)
node2、node3 上直接执行(不要引导):
CHANGE MASTERTOMASTER_USER='repl',MASTER_PASSWORD='repl'FORCHANNEL'group_replication_recovery';STARTGROUP_REPLICATION;⚠️ 从节点加入要求数据一致:若从节点已有与组不一致的数据,会卡在
RECOVERING。
最稳妥做法是从节点数据目录保持为空/全新,由组复制通过 binlog 或 clone 自动追赶。
全部加入后,在任意节点查询:
SELECT*FROMperformance_schema.replication_group_members;三个成员都应为ONLINE。
6.9 验证组复制
单主模式下主库自动切换验证:杀掉 node1 的 mysqld 进程:
systemctl stop mysqld# 在 node1 上模拟主库宕机在 node2 上观察:
SELECT*FROMperformance_schema.replication_group_members;-- node1 变为 UNREACHABLE / 数秒后被移出,node2 或 node3 自动变为 PRIMARYSHOWSTATUSLIKE'group_replication_primary_member';剩余成员会自动选举新主,业务连接切到新主后继续读写,全程无需人工介入。
把 node1 重新启动后,它也会自动重新加入组并追平数据:
STARTGROUP_REPLICATION;-- 若 start_on_boot=OFF 需手动执行组复制日常监控(任意成员执行):
SELECT*FROMperformance_schema.replication_group_members;-- 成员状态:ONLINE / RECOVERING ...SHOWSTATUSLIKE'group_replication_primary_member';-- 当前主节点SELECT*FROMperformance_schema.replication_group_member_stats;-- 各成员事务吞吐 / 冲突数| 关注项 | 含义 |
|---|---|
MEMBER_STATE | ONLINE正常;RECOVERING正在追赶;UNREACHABLE/ERROR异常 |
MEMBER_ROLE | 8.0 起显示PRIMARY(当前主)或SECONDARY |
COUNT_TRANSACTIONS_CHECKED/COUNT_CONFLICTS_DETECTED | 认证事务数与冲突数,冲突数增长要警惕并发写同一行 |
group_replication_primary_member | 当前主节点的成员 ID,与MEMBER_ID对照 |
6.10 分布式恢复(Distributed Recovery)
新成员START GROUP_REPLICATION后,状态会先停在RECOVERING,通过分布式恢复追赶数据:
- 方式一:基于 binlog 恢复。新成员向组内某个"捐助者(donor)"要 binlog,从它缺少的
GTID 处继续拉取。前提是 donor 上对应的 binlog还没被 purge。 - 方式二:基于 CLONE 插件。若新成员需要的 binlog 已被清理(所需 GTID 已被包含在
gtid_purged中),无法增量恢复,就需要用CLONE插件全量克隆donor 数据再继续。
这也是 6.5 中恢复账号要授BACKUP_ADMIN的原因。
-- 查看恢复通道的进度与报错SELECT*FROMperformance_schema.replication_connection_statusWHERECHANNEL_NAME='group_replication_recovery'\G6.11 多主模式与冲突检测
把group_replication_single_primary_mode = OFF即进入多主模式,所有成员都可写。
多节点并发修改不同行没有问题;但两个成员同时改同一行时:
- 后认证的事务检测到写集冲突,会被回滚并返回错误(提示事务冲突,业务需自行重试)。
- 因此多主模式要求业务写入按行尽量分散(如按用户 ID 分片),且所有表必须有主键——
没有主键的表无法生成写集,MGR 直接拒绝。
-- 切换多主模式需停组后所有节点改配置并重启,不是热切换SETGLOBALgroup_replication_single_primary_mode=OFF;7. 四种复制方式对比
| 特性 | 传统主从 | GTID | 半同步 | 组复制 MGR |
|---|---|---|---|---|
| 复制定位方式 | binlog 文件 + 位点 | 全局事务 ID | 基于 GTID | 基于 GTID + Paxos |
| 一致性级别 | 异步(可能丢数据) | 异步(可精确定位) | 至少 1 个从库 ACK | 多数派 ACK,强一致 |
| 可写节点 | 仅主 | 仅主 | 仅主 | 单主 1 个 / 多主全部 |
| 自动选主 | 否 | 需借助工具 | 需借助工具 | 是(单主模式) |
| 故障转移 | 手动找位点 | 手动但顺滑 | 手动但顺滑 | 自动 |
| 脑裂防护 | 无 | 无 | 无 | quorum 多数派 |
| 架构复杂度 | 低 | 低 | 中 | 高 |
| 网络开销 | 1 条 binlog 流 | 1 条 binlog 流 | 1 条流 + ACK 往返 | 组内广播 + 认证 |
| 额外端口 | 3306 | 3306 | 3306 | 3306 + 33061 |
| 事务提交延迟 | 低 | 低 | 每事务 +1 RTT | 更高(广播 + 认证) |
选型建议:
- 数据可少量丢失、切换可手动 → 传统主从 / GTID。
- 追求"尽量不丢"且接受手动切换 → GTID + 半同步。
- 要自动高可用、数据强一致 → 组复制(MGR)单主模式。
- 主从复制解决"读写分离 + 备份容灾",是最基础的复制形态。
- GTID给每个事务打上全局唯一编号,解决了主从切换"找位点难"的痛点。
- 半同步通过至少一个从库 ACK,把"必然丢数据"压缩到极小概率,超时降级保可用。
- 组复制用 Paxos 多数派共识实现了自动选主与强一致,是高可用的官方正解。
参考文档
- MySQL 8.0 Reference Manual :: 20 Group Replication
- MySQL 8.0 Reference Manual :: 20.2.1.5 Bootstrapping the Group
- MySQL 8.0 Reference Manual :: START GROUP_REPLICATION
- MySQL 8.0 Reference Manual :: Semi-Synchronous Replication
- MySQL 8.0 Reference Manual :: GTID 相关章节