为什么是 MGR
传统 MySQL 主从复制(异步/半同步)的三大痛点:
| 痛点 | 传统主从 | MGR |
|---|---|---|
| 故障切换 | 手动或靠 orchestrator/MHA | 自动选主切换 |
| 数据一致性 | 异步可能丢数据 | Paxos 强一致(多数派确认) |
| 脑裂风险 | 高(需外部仲裁) | 内核级防脑裂(多数派存活才可写) |
MySQL Group Replication(MGR,5.7.17+ GA,8.0 成熟)基于 Paxos 变种(MySQL XCom) 实现多节点状态机复制,保证组内数据强一致,原生高可用。
核心概念
┌─────────────────────────────────────────────────┐
│ Group (组, 奇数节点推荐) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Node-1 │ │ Node-2 │ │ Node-3 │ │
│ │ Primary │ │ Secondary │ │ Secondary │ │
│ │ (可读写) │ │ (只读) │ │ (只读) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ XCom (Paxos) 消息层 │
│ 每个事务需多数派(≥2/3)确认才提交 │
└─────────────────────────────────────────────────┘
- 单主模式(Single-Primary):只有一个节点可写,其余只读,自动选主(默认,最常用)
- 多主模式(Multi-Primary):所有节点均可写,需处理冲突检测
- XCom 层:基于 Paxos 的组通信引擎,负责节点发现、成员管理、消息有序广播
- 多数派(Majority):N 节点组可容忍
(N-1)/2节点故障;3 节点容忍 1 个宕机
部署前准备
# 三节点均执行(以 MySQL 8.0 为例)
# 1. 关闭冲突功能
-- 必须以下条件:
-- - 每张表必须有主键(无主键表无法在 MGR 中复制)
-- - 存储引擎必须为 InnoDB
-- - 必须开启 GTID
-- - 必须使用行格式 binlog(ROW)
# 2. 修改 my.cnf(每个节点不同 server_id 和 report_host)
cat >> /etc/my.cnf << 'EOF'
[mysqld]
server_id = 1 # 各节点不同: 1/2/3
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_format = ROW
binlog_checksum = NONE # MGR 要求
master_info_repository = TABLE
relay_log_info_repository = TABLE
transaction_write_set_extraction = XXHASH64
log_slave_updates = ON
skip_slave_start = ON
# MGR 专用配置
plugin_load_add = 'group_replication.so'
transaction_isolation = 'READ-COMMITTED' # 多主模式必须
group_replication_group_name = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" # 组UUID, 三节点一致
group_replication_start_on_boot = OFF
group_replication_local_address = "192.168.1.11:33061" # 各节点本机IP:端口
group_replication_group_seeds = "192.168.1.11:33061,192.168.1.12:33061,192.168.1.13:33061"
group_replication_bootstrap_group = OFF
group_replication_single_primary_mode = ON # 单主模式
group_replication_enforce_update_everywhere_checks = OFF
report_host = 192.168.1.11 # 各节点本机IP
EOF
systemctl restart mysqld
组名必须是合法 UUID 格式,且三节点完全一致。建议用
SELECT UUID()生成一个。
引导组复制
第一个节点(引导者)
-- 安装插件(如未自动加载)
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
-- 创建复制专用用户
SET SQL_LOG_BIN=0;
CREATE USER 'repl'@'%' IDENTIFIED BY 'ReplPass!2026' REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
SET SQL_LOG_BIN=1;
CHANGE REPLICATION SOURCE TO
SOURCE_USER='repl',
SOURCE_PASSWORD='ReplPass!2026',
SOURCE_HOST='192.168.1.11', -- 本机
SOURCE_PORT=3306,
GET_SOURCE_PUBLIC_KEY=1
FOR CHANNEL 'group_replication_recovery';
-- 引导组(仅第一个节点执行一次!)
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group = OFF;
-- 确认成员状态
SELECT * FROM performance_schema.replication_group_members;
-- MEMBER_STATE 应为 ONLINE
其他节点(加入者)
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
SET SQL_LOG_BIN=0;
CREATE USER 'repl'@'%' IDENTIFIED BY 'ReplPass!2026' REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
SET SQL_LOG_BIN=1;
CHANGE REPLICATION SOURCE TO
SOURCE_USER='repl',
SOURCE_PASSWORD='ReplPass!2026',
SOURCE_HOST='192.168.1.11', -- 任意在线成员均可
SOURCE_PORT=3306,
GET_SOURCE_PUBLIC_KEY=1
FOR CHANNEL 'group_replication_recovery';
-- 直接加入(不要 bootstrap)
START GROUP_REPLICATION;
SELECT * FROM performance_schema.replication_group_members;
验证
-- 查看组成员与角色
SELECT
MEMBER_ID, MEMBER_HOST, MEMBER_PORT,
MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members;
-- MEMBER_ROLE: PRIMARY / SECONDARY
-- 查看主节点(单主模式)
SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'group_replication_primary_member';
故障自动切换
单主模式下,Primary 宕机后,MGR 自动从 Secondary 中选举新 Primary:
# 模拟 Primary 宕机
systemctl stop mysqld # 在 Primary 节点执行
# 在存活节点查看(约 5-10 秒完成切换)
SELECT MEMBER_HOST, MEMBER_ROLE, MEMBER_STATE
FROM performance_schema.replication_group_members;
-- 原 Secondary 之一变为 PRIMARY,状态 ONLINE
切换过程:
- 故障节点被踢出组(超过
group_replication_member_expel_timeout超时) - 剩余节点重新选举 Primary(基于 UUID 字典序的优先级)
- 应用连接需重连到新 Primary(用 MySQL Router 或 VIP 透明切换)
配合 MySQL Router(透明路由)
# 安装 MySQL Router(应用层不需要知道哪个是 Primary)
mysqlrouter --bootstrap root@192.168.1.11:3306 --user=mysqlrouter
systemctl start mysqlrouter
# 应用连接 Router 的读写端口(默认 6446 写 / 6447 读)
# Router 自动把写请求路由到当前 Primary,读请求负载到 Secondary
推荐架构:MGR 三节点 + MySQL Router + 应用连接 Router 端口,实现完全透明的故障切换。
多主模式(谨慎使用)
-- 所有节点设置
SET GLOBAL group_replication_single_primary_mode = OFF;
SET GLOBAL group_replication_enforce_update_everywhere_checks = ON;
-- 重启组(先停所有节点,引导者改模式后重启)
多主模式要点:
- 每个节点独立接受写,XCom 保证全局顺序
- 冲突检测:同一行被两个节点同时修改 → 后提交的事务回滚(报错
ERROR 1180) - 要求
READ-COMMITTED隔离级别 - 外键、级联操作、大事务在多主下风险高
经验法则:99% 场景用单主模式。多主仅适合写少、无跨节点同行冲突、需要就近写入的全球部署。
监控与告警
关键状态指标
-- 1. 成员健康
SELECT MEMBER_HOST, MEMBER_STATE
FROM performance_schema.replication_group_members;
-- 所有应为 ONLINE;出现 RECOVERING/OFFLINE/ERROR 告警
-- 2. 待应用的事务队列(延迟指标)
SELECT COUNT_TRANSACTIONS_IN_QUEUE
FROM performance_schema.replication_group_member_stats
WHERE MEMBER_ID = (SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME='group_replication_primary_member');
-- 持续 > 0 表示有复制延迟
-- 3. 冲突/错误计数
SELECT COUNT_TRANSACTIONS_ROWS_VALIDATING, COUNT_CONFLICTS_DETECTED
FROM performance_schema.replication_group_member_stats;
Prometheus 监控
# mysqld_exporter 已暴露 MGR 指标
scrape_configs:
- job_name: 'mysql-mgr'
static_configs:
- targets: ['192.168.1.11:9104', '192.168.1.12:9104', '192.168.1.13:9104']
# 关键告警
groups:
- name: mysql-mgr
rules:
- alert: MGRMemberNotOnline
expr: mysql_group_replication_member_state{state!="ONLINE"} == 1
for: 1m
labels: { severity: critical }
- alert: MGRPrimaryMissing
expr: count(mysql_group_replication_primary_member > 0) == 0
for: 30s
labels: { severity: critical }
- alert: MGRReplicationLag
expr: mysql_group_replication_transaction_queue > 100
for: 2m
labels: { severity: warning }
常见故障处理
节点意外退出后重新加入
-- 在退出节点执行
STOP GROUP_REPLICATION;
START GROUP_REPLICATION;
-- 若报认证错误,可能需要:
RESET SLAVE ALL FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
脑裂后网络分区恢复
-- 少数派分区节点会被设为 ERROR 状态,需手动恢复:
STOP GROUP_REPLICATION;
-- 确认多数派分区已选出新 Primary 且数据最新
START GROUP_REPLICATION; -- 重新作为 Secondary 加入,自动追平数据
引导者永久丢失
-- 若原引导节点彻底不可用,在新 Primary 上无需 bootstrap
-- 只需确保 group_replication_bootstrap_group=OFF,正常 START 即可
-- 组 UUID 保持不变,新节点沿用原组名加入
与 InnoDB Cluster 的关系
MySQL InnoDB Cluster = MGR + MySQL Shell + MySQL Router 的完整高可用方案:
# 用 MySQL Shell 管理(比手动 SQL 简单)
mysqlsh
> dba.configureInstance('root@192.168.1.11:3306')
> var c = dba.createCluster('myCluster')
> c.addInstance('root@192.168.1.12:3306')
> c.addInstance('root@192.168.1.13:3306')
> c.status()
生产环境推荐直接用 InnoDB Cluster(Shell 管理),底层就是 MGR,但省去了手动配置引导、故障切换路由等繁琐步骤。
避坑清单
| # | 坑 | 症状 | 解决 |
|---|---|---|---|
| 1 | 表无主键 | 节点报错退出组 | MGR 要求每张表有主键;加主键后重新加组 |
| 2 | binlog_checksum 未关 | 启动失败 | 设 binlog_checksum=NONE |
| 3 | 引导节点误 bootstrap 两次 | 出现两个组/脑裂 | 仅第一个节点首次启动设 bootstrap_group=ON 一次 |
| 4 | 网络抖动频繁踢节点 | 成员反复 RECOVERING | 调大 group_replication_member_expel_timeout(默认 5s→30s) |
| 5 | 多主模式写冲突 | 事务回滚 ERROR 1180 | 避免跨节点同写一行;或改回单主 |
| 6 | 单主模式应用直连旧 Primary | 写入失败 | 应用经 MySQL Router 或 VIP 连接,不直连 IP |
| 7 | 大事务阻塞组 | 复制延迟飙升 | 拆分大事务;调大 group_replication_transaction_size_limit |
| 8 | 节点数据严重落后 | 追平超时 | 用克隆插件(clone)重建节点,比增量追平快 |
| 9 | SSL 未启用 | 复制用户明文 | REQUIRE SSL + 配置组通信 SSL |
| 10 | 偶数节点部署 | 脑裂时无法形成多数派 | 部署奇数节点(3/5),或加仲裁节点(Arbitrator) |
总结
MySQL MGR 把"高可用"从外部工具(MHA/orchestrator)下沉到数据库内核,核心要点:
- Paxos 多数派确认保证强一致,原生防脑裂(少数派自动只读)
- 单主模式自动选主,配合 MySQL Router 实现透明故障切换
- 每张表必须有主键、
binlog_format=ROW、binlog_checksum=NONE是硬性前提 - 奇数节点部署(3/5),容忍
(N-1)/2故障 - 监控成员状态 + 事务队列是关键告警指标
- 生产推荐 InnoDB Cluster(Shell 管理),底层即 MGR 但更易用
选型对比:中小团队要强一致高可用 → MGR/InnoDB Cluster;需要异地多活、海量写入 → 考虑 TiDB;纯读扩展、容忍秒级延迟 → 传统一主多从 + ProxySQL 仍简单有效。

