Skip to content

从 MGR 到故障切换:MySQL 高可用方案怎么落地

面试官问「讲一下 MySQL 的高可用方案」,很多人张口就报菜名:MHA、Orchestrator、MGR、InnoDB Cluster。再追问「主库挂了之后到底发生了什么」,就只剩「自动切换」四个字。

本文不讲概念堆砌,只推演一次真实故障的全过程,顺便把 MGR 的选主、故障探测、RPO/RTO 算清楚。

场景:主库突然挂了

假设三节点 MGR 集群,节点 A 是 Primary,节点 B 和 C 是 Secondary。某秒 A 的物理机断电,B 和 C 和 A 的组通信断开。

这时 B 和 C 需要判断两件事:

  1. A 是真挂了还是网络抖动?
  2. 谁来做新 Primary?

故障探测不是靠 ping

很多人以为 MGR 像 Keepalived 一样靠心跳超时做切换。MGR 的高可用基于 Paxos 的组通信协议(XCom),每个节点之间维持双向 TCP 连接,数据包交互相应。当节点 B 超过 group_replication_communication_timeout(默认 10s)没收到 A 的消息,B 会认为 A 失联。

但单个节点判断失联不够——MGR 需要多数派存活才能继续。如果只有 3 个节点,B 收到 C 的确认后,B 和 C 构成多数派(2/3),可以继续服务。此时组通信模块触发 自动选主(auto-rejoin)

选主规则:

  • 具有最高 group_replication_member_weight 的节点优先
  • 权重相同的情况下,按 group_replication_auto_increment_incrementgroup_replication_auto_increment_offset 排序
  • 如果还是相同,按 MEMBER_HOSTMEMBER_PORT 降序排列
bash
# 查看当前的 member_weight 配置
SELECT * FROM performance_schema.replication_group_members;
SELECT * FROM performance_schema.replication_group_member_stats;

一句话概括: 故障探测是组通信确认的,不是单纯的心跳超时。3 节点必须至少 2 个节点存活才能正常工作。

选主之后做了什么

新 Primary B 当选后,它的角色从 SECONDARY 变为 PRIMARY。这个变更通过组通信广播给 C(如果 C 还在)。此时 B 开始接收写入请求,C 作为新 Secondary 开始从 B 的 binlog 同步。

但 A 的数据还没追过来。如果 A 恢复后重新加入集群,它会经历:

  1. 检查自己的 GTID 集合与当前集群的 GTID 集合差距
  2. 如果差距超过 group_replication_clone_threshold(默认 50MB),触发 Clone Plugin 全量拷贝
  3. 如果差距小于阈值,自动通过增量 binlog 追赶
sql
-- 查看 GTID 差距
SELECT RECEIVED_TRANSACTION_SET, @@GLOBAL.GTID_EXECUTED
FROM performance_schema.replication_connection_status\G

MGR 的 RPO 和 RTO 到底是多少

这是面试追问最密集的部分。先说结论:

RPO = 0(在多数派存活的情况下)。因为 MGR 的单主模式下,事务在 Primary 提交前必须经过多数派节点的确认。A 提交了一条事务,B 和 C 也收到了。A 挂了,B 或 C 接管,这条事务不会丢。

唯一的例外:如果 A 写入了一条事务,还没广播给 B 和 C 就崩溃了,这条事务确实会丢失。但它在 A 自己也没提交(提交需要多数派确认),所以客户端看来这条事务根本没成功,不算丢失。严格意义上 RPO 为 0。

RTO 的组成

RTO = 故障探测时间 + 确认多数派时间 + 选主时间 + 路由切换时间
阶段典型耗时说明
故障探测5-15sgroup_replication_communication_timeout 默认 10s,可调小但容易误判
确认多数派1-2sB 和 C 互相确认彼此的存活状态
选主1-3s走 Paxos 的 Leader Lease 重新选举
Router 感知5-10sMySQL Router 默认每 5-10s 刷新一次元数据

总 RTO 大约 15-30s。如果调小 group_replication_communication_timeout 到 3s,RTO 可以压缩到 8-15s,代价是网络抖动时容易误判为脑裂。

对比一下其他方案:

方案RPORTO运维复杂度
异步复制 + MHA可能丢最后几秒数据30-60s高,需要配置 MHA 节点、VIP 漂移、binlog 补偿
半同步复制 + MHARPO=0(半同步不超时降级时)30-60s同上,半同步超时后自动降级为异步,RPO 又变不为 0
Orchestrator取决于复制模式10-30s中,支持 Web UI 和自动切换,但选主逻辑靠 Raft 需额外节点
MGR 单主RPO=015-30s低,原生支持,MySQL Shell 一行命令创建集群

脑裂保护:MGR 怎么防止双主

MGR 最怕的场景不是主挂了,而是主没挂但网络分区了——A 离线,B 和 C 选了新 Primary B,但 A 也没死透,还在接受写入。这时候会出现两个 Primary,数据就分叉了。

MGR 防止脑裂的机制非常直接:多数派原则。节点 A 失去与 B 和 C 的通信后,A 自己只有 1 票,构不成多数派(需要 2/3),所以 A 会自己把自己退化为只读模式,拒绝写入。

sql
-- 可以验证:当节点被组孤立时
SHOW STATUS LIKE 'group_replication_primary_member';
-- 这个节点会变成 super_read_only=ON
SHOW VARIABLES LIKE 'super_read_only';
-- 值为 ON,意味着即使有 SUPER 权限也写不进去

这是 MGR 比 MHA 更安全的地方——MHA 的脑裂防护完全依赖外部配置(VIP 的 ARP 广播、SSH 的隔离脚本),配置不到位就会有双写风险。

InnoDB Cluster 的完整形态

InnoDB Cluster = MGR(组复制)+ MySQL Router(智能路由)+ MySQL Shell(管理工具)。三件套一起用,才能实现"一条命令搭建高可用集群"的效果。

bash
# 用 MySQL Shell 创建集群
mysqlsh root@nodeA:3306
mysql-js> var cluster = dba.createCluster('myCluster')
mysql-js> cluster.addInstance('root@nodeB:3306')
mysql-js> cluster.addInstance('root@nodeC:3306')
mysql-js> cluster.status()

MySQL Router 的流量路由机制

  • Router 启动时从集群中拉取元数据,知道哪个节点是 Primary、哪些是 Secondary
  • 读写端口(默认 6446)自动路由到 Primary
  • 只读端口(默认 6447)在所有节点间负载均衡
  • 当 Primary 切换时,Router 通过定期刷新元数据来感知新 Primary 地址
mermaid
flowchart LR
    App -->|6446 读写| Router
    App -->|6447 只读| Router
    Router --> NodeA[Primary A]
    Router --> NodeB[Secondary B]
    Router --> NodeC[Secondary C]
    NodeA -.->|组通信| NodeB
    NodeA -.->|组通信| NodeC
    NodeB -.->|组通信| NodeC

踩坑经验

  • Router 配在应用服务器上而不是单独部署,否则 Router 本身是单点
  • 应用端连接池的 TTL 要设成小于 Router 的元数据刷新间隔
  • 如果 Router 版本和集群版本不一致,元数据可能解析失败,导致连接路由到错误节点

总结:选型要算清楚,不是越新越好

MGR 不是万能的。它牺牲了 30-50% 的写入吞吐来换取 RPO=0 和自动切换。如果你的业务场景满足以下条件,MGR 是当前最优解:

  • 数据一致性要求高(金融、交易、订单)
  • 节点间延迟 < 5ms(同机房部署,不能跨城)
  • 写入 QPS < 5000(单机写入本身不高,MGR 的多数派确认开销可以接受)

如果写入 QPS 在 5000-20000 的量级,或者节点跨机房部署,那异步复制 + MHA 仍然是合理选择——RPO 有限度地接受几分钟的数据丢失,但写入性能不受影响。如果数据量超过单机承载上限,先分库分表,再对每个分片做 MGR,这才是高可用 + 水平扩展的正确姿势。

参考

  • MySQL 官方文档:Group Replication 章节
  • MySQL 8.0 InnoDB Cluster 管理员指南
  • 《MySQL 实战 45 讲》——MGR 与组通信
  • 生产踩坑:某支付系统 MGR 单主模式线上故障复盘

手撕 → 框架 → 生产化,一步步把 AI Agent 工程化搞透。
粤ICP备2026104257号-1