☰
MySQL MGR高可用架构实战:原理、搭建与排坑指南
2026/10/3 14:31:31 网站建设 项目流程

1. 写在前面:为什么我最终选择了 MGR

聊到 MySQL 高可用,很多人的第一反应是主从复制加 keepalived,或者半同步复制加 MHA。这些方案我早年都折腾过,说实话,能跑,但心里始终不踏实。主从切换要写脚本,要处理延迟,要担心脑裂,还要手动改应用连接地址。直到后来在项目里真正用上 MySQL Group Replication(MGR),我才觉得“高可用”这三个字算是落到了实处。

MGR 是 MySQL 官方提供的插件式高可用方案,基于 Paxos 协议实现组内节点间的状态复制。它解决的问题很直接:任何一个节点挂了,组内剩余节点自动达成一致,选出新的主节点,数据不丢失,业务端几乎无感知。这个机制有点像几个人一起开会,每个人手里都有一份完整会议记录,主持人突然离席,大家举手投票再推一个主持人出来,会议继续开,记录一条不少。

如果你正面临这样的场景——核心业务库不想再忍受故障后的人工干预,不想天天盯着从库追主库延迟,或者你所在的公司已经接受了 MySQL 8.0 的版本约束,那么 MGR 是一个非常值得投入的选型。这篇文章我按照自己的实操经验,从原理到搭建再到排坑,完整写一遍。内容偏实战,命令可以直接复制,适合有一定 MySQL 基础、打算在生产环境尝试 MGR 的 DBA 或后端运维。

先说明白我的实验环境,后文所有操作都基于这套环境:

  • 操作系统:CentOS 7.9 / Rocky Linux 8.4 均可
  • MySQL 版本:8.0.36(MGR 在 8.0 系列已经非常成熟)
  • 节点数量:3 台(一主两从,组复制推荐奇数节点)
  • 服务器 IP:192.168.10.11、192.168.10.12、192.168.10.13
  • 端口:3306(MySQL)、33061(组通信端口)

2. MGR 核心机制与架构选型

2.1 MGR 到底是怎么工作的

MGR 本质上是一个 MySQL 插件,它依赖 Group Communication System(GCS)和 Paxos 协议来实现节点间的消息广播和一致性决策。你可以把 GCS 想象成一个内部消息总线,每个节点做的每一个事务提交动作,都要先广播给组里其他节点,超过半数节点确认后,这个事务才会真正提交。

这里有个关键点,MGR 的复制不是传统的异步复制,也不是普通的半同步,而是基于共识协议的状态机复制。每个节点维护一份相同的事务执行序列,只要某个事务在多数节点上提交,那么即使有节点宕机,已提交事务也不会丢。这个特性让 MGR 天然具备强一致性的数据安全基础,和传统主从复制那种“主库提交了、从库可能还差十万八千里”的体验完全不同。

结合我的使用经验,用生活化的类比解释就是:传统主从复制是“领导拍板,下属事后抄笔记”,抄得快慢全看网速和运气;MGR 是“全员投票,过半同意才拍板”,虽然单事务延迟理论上会高一点,但数据可靠性完全不是一个级别。

MGR 内部还区分了两种通信模式:

  • 单主模式(Single-Primary):组内只有一个节点可写,其他节点只读。这个模式适合大多数业务场景,应用端不需要处理写分流。
  • 多主模式(Multi-Primary):组内所有节点都能写,MySQL 会自动处理写冲突。听着很爽,但对表的主键要求非常严格,而且事务冲突检测带来的性能开销明显,我个人的建议是,除非你真的需要多节点并发写入,否则老老实实用单主。

2.2 为什么节点数量选奇数

MGR 的可用性判断依赖多数派投票。如果组内有 3 个节点,允许挂 1 个;有 5 个节点,允许挂 2 个。偶数节点虽然也可以组,但会出现一个尴尬的情况:4 个节点挂 2 个后,剩余 2 个无法形成多数派,整个组就只读了。而 3 节点和 4 节点在容错能力上一样都只允许挂 1 个,却多花钱多维护一个节点。所以,3 节点是性价比最高的起步配置,5 节点是追求更高可用性的选择。

组复制的数据流方向是:应用写入 Primary 节点 → Primary 将事务广播给所有 Secondary → 每个节点验证事务并执行 → 回执给 Primary → 多数派确认后 Primary 提交事务。也就是说,每个 Secondary 节点上都有完整数据,随便挑一个出来都能承担读流量,这也是 MGR 能顺带做读写分离的基础。

2.3 MGR 与 MHA、半同步复制的取舍

我接触过不少从传统高可用方案迁移过来的团队,大家在选型前都会纠结一阵。我把我的对比心得整理成一张表:

方案数据一致性故障切换时间维护复杂度需要脚本/中间件适用场景
异步主从 + keepalived可能丢数据秒级~分钟级低是可以接受少量丢失的日志/报表库
半同步 + MHA基本不丢,极端情况可能丢10秒~30秒中是核心业务库但可容忍短暂中断
MGR 单主强一致,不丢事务秒级自动切换中否核心交易、订单、账户类业务
分布式数据库(如 TiDB)强一致秒级高否超大集群、需水平扩展的互联网业务

MGR 不是万能的,它需要 MySQL 8.0 以上,对网络延迟敏感,DDL 有过一些限制(后面会讲)。但如果你已经在 MySQL 生态里且能接受 8.0,MGR 是官方支持、无额外中间件、切换机制透明的首选。

3. 搭建前的环境准备与参数设计

3.1 三台机器的初始化配置

我通常使用 Rocky Linux 8 或 CentOS 7 作为操作系统,但这两个系统自带的包管理源里 MySQL 版本可能不是最新的,所以推荐用 MySQL 官方 Yum 源安装。

第一步,三台机器都要做基础初始化。我一般先把 SELinux 设为 permissive,关闭 firewalld,或者放行对应端口。组复制用到两个端口:3306 是 MySQL 服务端口,33061 是组通信专用端口,如果开了防火墙,这两个端口都得放行。生产环境不建议直接关防火墙,你按自己公司的安全策略放行即可。

然后配置主机名和 hosts,让三台机器之间可以通过主机名互相解析。这个步骤很多人会忽略,但 MGR 在成员间通信时如果解析不了主机名,会陷入各种奇怪的连接超时状态。

# 在每台机器上执行,设置主机名 hostnamectl set-hostname mgr-node1 hostnamectl set-hostname mgr-node2 hostnamectl set-hostname mgr-node3 # /etc/hosts 加入三行 192.168.10.11 mgr-node1 192.168.10.12 mgr-node2 192.168.10.13 mgr-node3

同步时间也很重要,Paxos 协议虽然不强制要求物理时钟完全一致,但时钟偏移过大会影响事务时间戳和 GTID 的判断。我用 chrony 做时间同步:

yum install -y chrony systemctl enable --now chronyd chronyc sources -v

这里要插一句,MGR 对网络质量有硬性要求。如果三个节点跨机房部署,延迟超过几十毫秒,每个事务都要等多数派确认,性能会非常难看。我建议 MGR 的节点最好在同一个机房同一个内网段内,别玩跨城集群,那不是 MGR 擅长的场景。

3.2 MySQL 8.0 安装与 my.cnf 配置

安装 MySQL 8.0 的部分我就不逐步截图了,直接说结果。用官方 Yum 源安装后,需要修改 /etc/my.cnf。我第一次搭建 MGR 时,因为参数少配了一个,导致节点一直加入不了组,日志里报错也是模棱两可。所以我先把完整配置贴出来,再逐个解释。

[mysqld] server_id = 1 gtid_mode = ON enforce_gtid_consistency = ON binlog_checksum = NONE log_bin = binlog log_slave_updates = ON binlog_format = ROW master_info_repository = TABLE relay_log_info_repository = TABLE relay_log_recovery = ON # 组复制专用 plugin_load_add = 'group_replication.so' group_replication_group_name = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' group_replication_start_on_boot = OFF group_replication_local_address = 'mgr-node1:33061' group_replication_group_seeds = 'mgr-node1:33061,mgr-node2:33061,mgr-node3:33061' group_replication_single_primary_mode = ON group_replication_enforce_update_everywhere_checks = OFF

每台机器注意修改三个地方:server_id必须不同,group_replication_local_address用各自主机名,另外,group_replication_group_name必须是合法的 UUID 格式。这个 UUID 你可以用 Linux 的uuidgen命令生成一个,三台机器保持一致。

逐条说几个容易踩坑的参数:

  • binlog_checksum = NONE:组复制官方要求禁掉 binlog 校验和,否则节点同步时可能因为校验不一致被踢出组。
  • binlog_format = ROW:必须用行级复制,这是组复制的基础前提。
  • log_slave_updates = ON:从节点也要记录 binlog,因为组复制每个节点都可能被提升为主。
  • relay_log_recovery = ON:中继日志崩溃时自动恢复,减少人工干预。
  • group_replication_start_on_boot = OFF:我建议先关掉,等集群初始化完成后再视情况开启。不然 MySQL 一启动就想着加入组,如果组还没初始化好,很容易反复报错。

配置完成后,用systemctl start mysqld启动服务。首次启动会生成临时密码,用grep 'temporary password' /var/log/mysqld.log拿到后登录,然后先修改 root 密码。这里要注意,MySQL 8.0 默认的密码校验策略很强,简单的密码可能被拒绝,可以先按提示设置一个复杂密码,后面再调策略。

3.3 三个节点的数据初始化

MGR 要求所有节点的数据初始状态一致。最简单的方式是:先在第一个节点上创建好业务库和测试表,也可以让它空库初始化,但生产环境一定要保证三个节点的 binlog 位点一致。

实操里我是这样做的:

  1. 在 node1 上用 mysql 客户端创建用于复制的用户和 MGR 管理用户。
  2. 在 node1 上执行RESET MASTER(保证空环境干净,但生产环境慎用!)。
  3. 不往 node1 写任何业务数据,直接用它作为 Seed 节点初始化组。
  4. node2 和 node3 以全新实例加入,通过组的复制能力自动把 node1 的数据同步过来。

如果是已经有存量数据的库,那就得用mysqldump先导出一份一致性快照,恢复到 node2、node3 后,再启动组复制。顺序不能乱。

我把标准的初始化 SQL 写在这里。登录 MySQL 后执行:

-- 创建组复制专用账号 SET SQL_LOG_BIN=0; CREATE USER 'repl'@'%' IDENTIFIED BY 'YourStrongPass@123'; GRANT REPLICATION SLAVE, BACKUP_ADMIN ON *.* TO 'repl'@'%'; GRANT GROUP_REPLICATION_ADMIN ON *.* TO 'repl'@'%'; SET SQL_LOG_BIN=1;

SET SQL_LOG_BIN=0是为了不让这些账号创建操作进入 binlog,否则会被复制到其他节点,造成账号混乱。这个细节我第一次没注意,结果三个节点的复制账号权限不一致,折腾了半小时。

接着在 node1 上安装组复制插件并初始化组:

INSTALL PLUGIN group_replication SONAME 'group_replication.so'; SET GLOBAL group_replication_bootstrap_group = ON; START GROUP_REPLICATION; SET GLOBAL group_replication_bootstrap_group = OFF;

bootstrap_group这个变量只能由第一个节点在初始化组时打开,打开后要立刻关掉。它就像“创建俱乐部”的开关,如果其他节点也误开了,会导致出现两个视图不一致的“平行宇宙”,这是 MGR 最常见的脑裂根源。

4. 单主模式集群搭建全流程实录

4.1 启动 Seed 节点并验证状态

执行完上面的 SQL 后,在 node1 上检查组复制状态:

SELECT * FROM performance_schema.replication_group_members;

如果一切正常,你会看到类似这样的输出:一个 ONLINE 状态的成员,角色是 PRIMARY,另外两个节点还没加入。

此时 node1 就是组里的“元老”。接下来我们要让 node2、node3 加入这个组。

4.2 第二、三节点加入组的完整步骤

node2 和 node3 的 my.cnf 改好、MySQL 启动后,先要设置group_replication_group_seeds指向所有节点,然后同样安装插件,创建复制账号,最后执行START GROUP_REPLICATION。注意,非第一个节点千万不要执行bootstrap_group。

具体 SQL 如下,node2 和 node3 分别执行:

INSTALL PLUGIN group_replication SONAME 'group_replication.so'; SET SQL_LOG_BIN=0; CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED BY 'YourStrongPass@123'; GRANT REPLICATION SLAVE, BACKUP_ADMIN ON *.* TO 'repl'@'%'; GRANT GROUP_REPLICATION_ADMIN ON *.* TO 'repl'@'%'; SET SQL_LOG_BIN=1; START GROUP_REPLICATION;

执行START GROUP_REPLICATION后,节点会通过 group_seeds 里的地址去联系 node1,请求加入组。node1 收到请求后,会做一系列检查:GTID 是否一致、binlog 格式、插件版本、账号权限等等。任何一项不满足,加入都会失败。

node2、node3 都执行完成后,再查一次replication_group_members:

SELECT * FROM performance_schema.replication_group_members;

正常的话三个节点都是 ONLINE,其中 node1 的 MEMBER_ROLE 是 PRIMARY,node2、node3 是 SECONDARY。单主模式下,SECONDARY 节点上的写入操作会直接被拒绝,报错ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option。

4.3 验证数据复制与自动故障切换

搭建完成的下一步当然是验证。我在 node1 上创建一个测试库和表,插入几条数据:

CREATE DATABASE demo; USE demo; CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(100)); INSERT INTO t1 VALUES (1, 'mgr'), (2, 'test');

然后分别到 node2、node3 上SELECT * FROM demo.t1;,发现数据已经自动同步过去。这个同步不是异步延迟很久,而是写入 node1 提交后,node2、node3 基本实时可见(强一致性意味着提交时多数派已经确认)。

接下来模拟故障。我把 node1 的 MySQL 直接 kill 掉:

systemctl stop mysqld

等待几秒后,在 node2 上查成员状态:

SELECT * FROM performance_schema.replication_group_members;

你会看到 node1 变成 UNREACHABLE,node2 和 node3 中的某一个会自动被提升为 PRIMARY。自动切换过程不需要任何外部脚本,完全是组复制内部通过 Paxos 协商出来的。新的主节点选出来后,你再往新的主节点写入数据,其他节点继续同步。

这里有个小细节:如果你用的是 MySQL Shell 或者较新的客户端,可能还会看到MEMBER_STATE为ONLINE但MEMBER_ROLE变化的过程。切换后,应用端连接串如果写的是旧主 IP,就会连不上。所以生产环境最好用 VIP 或 DNS 指向当前主节点,或者通过 MySQL Router 做自动路由。MGR 本身不提供 VIP,你需要自己配 Keepalived 或者用 MySQL Router。

4.4 故障节点重新加回组的正确姿势

node1 恢复后,不能直接执行START GROUP_REPLICATION,因为它之前是 PRIMARY,但现在已经有了新的 PRIMARY(比如 node2),node1 需要以 SECONDARY 身份重新加入。

正确的操作是在 node1 上执行:

SET GLOBAL group_replication_single_primary_mode = ON; START GROUP_REPLICATION;

如果之前 node1 是被kill -9强杀的,日志可能残留一些连接状态,保险起见,先执行:

STOP GROUP_REPLICATION; RESET MASTER; -- 仅适用于从节点且确认数据可由组内补齐时,慎重

然后再重新设置 GTID 同步。实际上 MGR 会自动从组内其他节点获取缺失的 GTID 事务,所以大多数情况下,直接START GROUP_REPLICATION就能追平数据并回到 ONLINE 状态。如果因为 binlog 被清理导致无法追平,那就需要重新做一次全量备份恢复,具体我放在后面常见问题章节里讲。

5. 多主模式、读写分离与参数调优

5.1 多主模式配置差异

如果你想试多主模式,改动不复杂:三台节点配置里都设置group_replication_single_primary_mode = OFF,并开启group_replication_enforce_update_everywhere_checks = ON。然后所有节点都执行START GROUP_REPLICATION,这样每个节点都是 PRIMARY 角色。

但多主模式有一个非常硬性的要求:所有表必须有主键,否则组复制会拒绝写入。这个限制是因为多主模式下,事务冲突检测依赖主键来定位行数据。如果一个表没有主键,insert、update、delete 都可能无法正确检测冲突,导致出现数据不一致。

我在测试环境开过多主模式,同时向两个节点插入相同主键的数据,会有一个事务报死锁。这其实是正常现象——MGR 在多主模式下能检测出写冲突,并让其中一个事务失败回滚,保证数据最终一致。但从业务角度看,报错就是报错,你得在应用层做好重试机制。因此,我的结论是:多主模式适合“多写少冲突”的业务,比如不同业务模块的数据天然分片,各写各的。如果所有业务都集中在同一张表上,老老实实单主更靠谱。

5.2 基于 MGR 的读写分离方案

单主模式下,SECONDARY 节点可以用来做读扩展。但应用层必须知道哪个节点是主、哪些是从。最省事的方案是引入 MySQL Router,它是 MySQL 官方的中间件,可以自动感知 MGR 的拓扑变化。

部署 MySQL Router 时,只需要配置一个引导命令:

mysqlrouter --bootstrap user:password@node1:3306 --directory /opt/mysql-router

Router 会读取 MGR 的元数据,自动生成读写端口 6446 和只读端口 6447。应用读写分离时,写走 6446,读走 6447。当主节点切换后,Router 会在秒级感知并更新路由。这个方案比我以前用 ProxySQL 手动配 MGR 监控简单得多,官方支持度也好。

不过如果你已经有用得很顺手的 ProxySQL,它同样支持 MGR 的自动检测,只是配置项比较多。我个人建议:新项目直接上 MySQL Router,老项目能不动就别动。

5.3 关键参数调优与性能影响

MGR 相比普通异步复制,最大的性能开销在于每个事务都要经过组通信确认。在低并发下这个开销不明显,但高并发写入时,吞吐量会有一定下降。我从实践中总结了几个影响较大的参数:

  • group_replication_flow_control_mode:默认是 QUOTA,组复制会基于节点积压情况做流控。如果从节点应用日志的速度跟不上,主节点会自动限制写入速度。对延迟敏感的业务,可以调整为 DISABLED,但这会增加从节点堆积风险,不建议轻易关。
  • group_replication_flow_control_recovery_threshold:控制恢复过程中的积压阈值,默认 25000,即积压超过 25000 个事务才开始限流。这个值可以按需调大,比如 50000,减少限流触发频率。
  • group_replication_transaction_size_limit:默认上限是 150MB,超大事务直接报错。如果你的业务有大批量导入,记得把这个值调大。
  • innodb_flush_log_at_trx_commit = 1和sync_binlog = 1:这两个是保证节点本地数据不丢的基础,MGR 已经强依赖 binlog,不能再为了性能把它们调成 0。

调优思路是:先保持默认跑业务,用监控看节点间延迟replication_group_member_stats里的COUNT_TRANSACTIONS_IN_QUEUE,如果这个值持续增长,说明从节点应用跟不上,再考虑流控参数和从节点硬件。

6. 常见问题与排查技巧实录

6.1 节点一直显示 RECOVERING 怎么办

新手遇到最多的状态就是成员一直卡在 RECOVERING,永远进不了 ONLINE。这通常是因为节点间的 GTID 差异过大,或者复制账号权限不足,无法从其他节点拉取二进制日志。

排查步骤我固定是这样:

  1. 看当前的复制状态:

    SELECT * FROM performance_schema.replication_connection_status\G

    重点看LAST_ERROR_MESSAGE。

  2. 看通道名:

    SELECT CHANNEL_NAME, SERVICE_STATE FROM performance_schema.replication_connection_status;

    MGR 的复制通道名是group_replication_applier和group_replication_recovery。如果 recovery 通道报错,基本都是连接不上源节点。

  3. 确认账号权限:

    SHOW GRANTS FOR 'repl'@'%';

    必须包含GROUP_REPLICATION_ADMIN、REPLICATION SLAVE、BACKUP_ADMIN。

如果日志里报的是The donor and joiner are in different states,那就是两个节点的 GTID 集合差距太大。解决思路:把新的节点先用mysqldump从主节点导一份数据恢复,确保起点一致,再START GROUP_REPLICATION。别指望 MGR 能像传统主从那样只要 binlog 还在就能自动补全,组复制的自动补偿是基于 GTID 的,如果 binlog 被清理过,或者数据从一开始就不一样,它没法无中生有。

6.2 事务提交报错:不允许写操作

单主模式下,应用偶然把写请求发到了 SECONDARY 节点,会报read-only或super-read-only。这本身不是故障,但需要你可以确认一下当前真实主节点是哪个:

SELECT MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members WHERE MEMBER_ROLE='PRIMARY';

如果应用持续报这个错,不用怀疑,就是路由没切过来。你需要检查 MySQL Router 或负载均衡配置是否已经感知到新主。还有一种可能:你明明连的是主节点,但报错说只读。那大概率是节点刚从 SECONDARY 被提升为 PRIMARY,read_only参数还没来得及刷新。MGR 在切换时会自动设置,但如果你的 my.cnf 里显式写死了read_only = ON,组复制就没法覆盖它。所以,在搭建时千万别在配置文件里固定read_only参数,交给 MGR 动态管理。

6.3 节点被踢出组的常见原因

MGR 有一个仲裁机制,如果某个节点与其他节点失联超过阈值(默认group_replication_communication_max_message_size相关或检测超时),它会被标记为 UNREACHABLE,然后被移出组。被移出后,节点上的 MySQL 实例会进入超级只读模式,需要手动干预。

常见诱因:

  • 网络抖动或者防火墙拦了 33061 端口。
  • 大事务执行导致节点长时间无响应,被误判为故障。
  • 磁盘满导致 binlog 写不进去。

排查时先看错误日志:

tail -100 /var/log/mysqld.log | grep -i 'group replication'

如果是网络问题,修好网络后执行START GROUP_REPLICATION即可重新加入。如果是大事务问题,建议把事务拆分,并在应用层设置合理的innodb_lock_wait_timeout。

6.4 关于 SSH、数据库连接报错的特别提醒

写到这里突然想到一个热门搜索词在讲 MySQL SSL 连接错误。如果你在 MGR 环境里用客户端连接时报 SSL 相关错误,大概率是 MySQL 8.0 默认开启了 SSL,但客户端和服务端证书不匹配。MGR 内部的节点通信默认也是使用 SSL 的,MySQL 会自签证书。如果你在三台机器上分别初始化了数据目录,它们各自生成的证书并不一样。

为了避免组复制因证书问题连不上,可以在配置里加一行:

group_replication_ssl_mode = DISABLED

或者,推荐更安全的做法:统一使用同一套自建 CA 签发的证书,并配置group_replication_recovery_ssl_ca、group_replication_recovery_ssl_cert、group_replication_recovery_ssl_key。

我每次搭建生产环境都采用统一证书的方式。虽然配置麻烦一点,但网络链路上数据是加密的,符合大部分公司的安全审计要求。

6.5 现场实录:一次 DDL 引发的全组阻塞

最后分享一个印象深刻的真实故障。那时我已经把 MGR 跑上线,某天凌晨业务同学要在线上库执行一个 ALTER TABLE 加字段。当时我在主节点执行了 DDL,理论上 DDL 是复制到从节点执行的,但因为我们用的是 MySQL 8.0.2x,还没有支持在线 DDL 与组复制的完美协同,导致 DDL 在主库执行完,从库却卡在等待 MDL 锁。更麻烦的是,组复制在group_replication_enforce_update_everywhere_checks关闭时,DDL 会在所有节点串行执行,一旦某个节点卡住,整个组的复制队列全部积压。

那一次处理了快半小时。后来我学乖了,规范了 DDL 流程:低峰期执行,先在从节点上SET SESSION sql_log_bin=0的方式跳过组复制,手工执行一遍 DDL,确认不影响后,再在主节点执行并让复制自然同步。虽然这招有点绕,但能最大限度降低 DDL 对 MGR 的影响。

另外,8.0 的原子 DDL 特性在这里也需要注意,它虽然保证了 DDL 要么完全成功要么完全回滚,但组复制环境里一旦 DDL 在某个节点失败,整个组的事务应用都会被阻塞,直到异常节点被移除。

7. 监控、备份与日常运维心得

7.1 监控 MGR 状态的关键指标

MGR 日常监控比传统主从要多看几个视图。我最常用的是这三个:

-- 成员状态与角色 SELECT * FROM performance_schema.replication_group_members; -- 每个节点的事务队列情况 SELECT MEMBER_ID, COUNT_TRANSACTIONS_IN_QUEUE, COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE, COUNT_TRANSACTIONS_CHECKED, COUNT_CONFLICTS_DETECTED FROM performance_schema.replication_group_member_stats; -- 复制通道状态 SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_MESSAGE FROM performance_schema.replication_connection_status;

COUNT_TRANSACTIONS_IN_QUEUE是核心指标,必须盯紧。如果它持续增长,说明节点已经跟不上主库的写入速度,接下来就会触发流控,影响业务。

建议把这些指标接到 Prometheus + Grafana 或 Zabbix,告警阈值我一般这样设:

指标告警阈值说明
节点状态非 ONLINE必须告警
事务队列积压> 5000可能触发流控,需关注
冲突事务数持续增长多主模式下需要重构业务
主节点切换任一节点角色变为 PRIMARY评估切换原因

7.2 备份策略如何配合 MGR

MGR 提供的是高可用,但它并不替代备份。我见过有人以为 MGR 三个节点互相同步,就等于有三份备份了,这想法非常危险。万一某个节点上执行了误删除操作,由于组复制会自动把删除同步到所有节点,三份数据会同时被删,根本没有回退余地。

所以,备份还是得照做。建议在 SECONDARY 节点上用mysqldump做逻辑备份,或者用物理备份工具 XtraBackup 做全量备份加 binlog 增量。备份不会影响主节点性能,从节点本身就有完整数据,是天然的备份源。

恢复演练也要定期做。MGR 集群相对传统主从更复杂,如果不提前演练,真出问题时会手忙脚乱。我每个季度都会挑一个闲置环境,把备份文件恢复成一个独立实例,然后模拟“整个集群数据全部损坏”的场景,测试恢复流程的可行性。

7.3 组复制与 MySQL Router 的日常维护

日常运维中最常见的操作是滚动升级 MySQL 小版本。步骤是:先对一个 SECONDARY 节点停机升级,启动后确认它重新加入组并追平数据,然后依次处理下一个 SECONDARY,最后处理 PRIMARY。升级 PRIMARY 时会触发一次自动切换,业务会有秒级闪断,需要提前通知应用方。

如果你用了 MySQL Router,升级主节点后检查一下 Router 日志,确认它已经把流量切到新主。我遇到过一次 Router 缓存没刷新,导致写流量仍然打到旧主上,旧主此时是只读状态,应用直接报错。解决办法是重启 Router 服务,或者手动执行mysqlrouter --bootstrap重新引导。

8. 踩坑清单与最终建议

写到最后,我把这几年折腾 MGR 的坑集中列出来,每一条都是真金白银换来的:

  1. 不要在一个 MGR 组里混合不同大版本的 MySQL,比如 8.0.20 和 8.0.36 混用。组复制的协议在细节上有改进,混跑容易出诡异问题。
  2. 不要把group_replication_group_name写成随意字符串,必须要标准 UUID 格式,否则插件启动直接报错。
  3. 不要忘了在从节点设置group_replication_start_on_boot = OFF,等集群稳定后再决定要不要设置 ON。否则 MySQL 意外重启时,如果组里恰好只剩一个节点,它可能会尝试独立启动组,造成脑裂。
  4. 不要用公网 IP 做组通信地址,组复制对延迟和丢包非常敏感,跨公网部署基本不可用。
  5. 不要在 MGR 组里使用CREATE TABLE ... LIKE加临时表的方式做备份恢复,避免产生 GTID 空洞。如果真出现 GTID 空洞,需要手动SET GTID_NEXT处理,很麻烦。
  6. 不做任何操作前,先确认performance_schema是开启的。MGR 的监控全部依赖于 performance_schema,如果它在 my.cnf 里被禁用了,组复制状态视图全是空。

关于未来,如果你所在团队已经计划向云原生和容器化转型,MGR 在 Kubernetes 里也可以跑,只是运维复杂度指数级上升。一般中小团队建议还是以传统部署方式为主,省心。

这篇文章从原理到实操再到排坑,覆盖了我个人多次搭建 MGR 的核心积累。如果你照着做一遍,大概率能跑出一个可用的三节点集群。过程中如果遇到我没写到的问题,欢迎把错误日志里的关键词拿来一起分析,很多组复制问题通过日志定位比查文档更直接。最后想说的是,MGR 绝不是银弹,它有自己的脾气,摸透了,它就是那个能让你半夜少接电话的可靠伙伴。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询