MySQL MGR配合MySQL-router实现innodb-cluster原创
# 0. 先满足前置条件,否则 START GROUP_REPLICATION 一定失败
MGR 有一组硬性前提,不满足时报错信息往往指向别处,很容易排查半天。建集群前逐条确认:
版本说明
本文写于 2022-03,基于 MySQL 8.0 Group Replication。
MGR 的核心机制(Paxos 协议、单主/多主模式)未变,经 2026-07 复核仍适用;8.0 后续小版本对 MGR 的自动化运维(如 group_replication_communication_stack 参数、Clone 插件配合分布式恢复)有增强,新部署建议一并核对官方最新文档。
[mysqld]
server_id = 1 # 组内每个节点必须唯一
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_format = ROW
log_bin = mysql-bin
log_replica_updates = ON # 8.0.26 前叫 log_slave_updates,必须开
2
3
4
5
6
7
还有一条配置检查不出来、只会在运行时炸的:所有表必须有主键或非空唯一键。无主键表在 MGR 下写入直接失败,先扫一遍:
SELECT t.TABLE_SCHEMA, t.TABLE_NAME
FROM information_schema.TABLES t
LEFT JOIN information_schema.TABLE_CONSTRAINTS c
ON c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME AND c.CONSTRAINT_TYPE = 'PRIMARY KEY'
WHERE c.CONSTRAINT_NAME IS NULL
AND t.TABLE_SCHEMA NOT IN ('sys','mysql','performance_schema','information_schema')
AND t.TABLE_TYPE = 'BASE TABLE';
2
3
4
5
6
7
预期输出:空集。
# MGR 部署
# my.cnf配置参数
单主配置
#--- group replication settings ---
plugin-load = "group_replication.so"
transaction-write-set-extraction = XXHASH64
report_host = 192.0.2.11
binlog_checksum = NONE # 仅 8.0.20 及更早需要;8.0.21+ MGR 已支持 CRC32,新版本可删掉这行
loose_slave_preserve_commit_order = on
loose_group_replication = FORCE_PLUS_PERMANENT
loose_group_replication_group_name = "f0d9e877-661b-487c-a955-7fae37a5c2bd"
loose_group_replication_compression_threshold = 100000 # mysql8.0.11后默认值为1000000字节,1M
loose_group_replication_flow_control_mode = 0
loose_group_replication_single_primary_mode = 1
loose_group_replication_transaction_size_limit = 331350016
loose_group_replication_member_expel_timeout = 20
loose_group_replication_unreachable_majority_timeout = 20
loose_group_replication_start_on_boot = off
loose_group_replication_local_address = '192.0.2.11:23502' #端口跟mysql端口不同即可
loose_group_replication_group_seeds = '192.0.2.12:23501,192.0.2.11:23502,192.0.2.13:23503'
loose_group_replication_ip_allowlist = '192.0.2.0/24' # 8.0.22 起 ip_whitelist 已弃用,改名 ip_allowlist
loose_group_replication_bootstrap_group = off
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
多主配置
##--- group replication settings 多主模式---
plugin-load = "group_replication.so"
transaction-write-set-extraction = XXHASH64
report_host = 192.0.2.15
binlog_checksum = NONE # 仅 8.0.20 及更早需要;8.0.21+ MGR 已支持 CRC32,新版本可删掉这行
loose_slave_preserve_commit_order = on
loose_group_replication = FORCE_PLUS_PERMANENT
loose_group_replication_group_name = "b2c8d3e1-4f5a-11ee-9c11-0242ac120002" # 必须是一个合法且组内一致的 UUID,用 SELECT UUID() 生成,不能填全零
loose_group_replication_compression_threshold = 100000 # mysql8.0.11后默认值为1000000字节,1M
loose_group_replication_flow_control_mode = 0
loose_group_replication_single_primary_mode = 0
loose_group_replication_enforce_update_everywhere_checks = ON # 比单主多了这一行
loose_group_replication_transaction_size_limit = 331350016
loose_group_replication_member_expel_timeout = 20
loose_group_replication_unreachable_majority_timeout = 20
loose_group_replication_start_on_boot = off
loose_group_replication_local_address = '192.0.2.15:23306'
loose_group_replication_group_seeds = '192.0.2.15:23306,192.0.2.16:23306,192.0.2.17:23306'
loose_group_replication_ip_allowlist = '192.0.2.0/24' # 8.0.22 起改名;不要写 0.0.0.0/0,等于对全网开放组通信端口
loose_group_replication_bootstrap_group = off
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1.先创建一个用户
create user 'repl'@'172.16.0.%' identified by 'xxxxxxxxx';
# 再进行授权
grant REPLICATION SLAVE on *.* to 'repl'@'172.16.0.%' ;
# 2.安装插件
install plugin group_replication soname 'group_replication.so';
show plugins;
select * from INFORMATION_SCHEMA.PLUGINS where PLUGIN_NAME like '%group_replication%';
INSTALL PLUGIN clone SONAME 'mysql_clone.so'; #可选
# 3.配置master实例
1)查看当前的group replication相关参数是否配置有误
show global variables like 'group%';
2)启动 group_replication_bootstrap_group
SET GLOBAL group_replication_bootstrap_group=ON;
3)配置MGR
SET GLOBAL group_replication_ip_allowlist = '192.0.2.0/24';
-- 8.0.23 起 CHANGE MASTER TO 已弃用,用新语法:
CHANGE REPLICATION SOURCE TO
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '<password>'
FOR CHANNEL 'group_replication_recovery';
2
3
4
5
6
7
这一步在配什么:group_replication_recovery 是分布式恢复通道——新节点加入组时,靠这个通道从已有节点把落后的数据补齐。它和业务复制无关,但配错(用户名密码不对、账号没有 REPLICATION SLAVE 权限)会让节点永远停在 RECOVERING,而错误信息只会出现在错误日志里,replication_group_members 里看不出原因。
4)启动MGR
start group_replication;
5)关闭 group_replication_bootstrap_groups
SET GLOBAL group_replication_bootstrap_group=OFF;
# 验证
SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members;
2
预期输出(三个节点全部 ONLINE,单主模式下一个 PRIMARY 两个 SECONDARY):
+-------------+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE |
+-------------+-------------+--------------+-------------+
| 192.0.2.11 | 3306 | ONLINE | PRIMARY |
| 192.0.2.12 | 3306 | ONLINE | SECONDARY |
| 192.0.2.13 | 3306 | ONLINE | SECONDARY |
+-------------+-------------+--------------+-------------+
2
3
4
5
6
7
MEMBER_STATE 的取值就是排障入口:
| 状态 | 含义 | 通常的原因 |
|---|---|---|
ONLINE | 正常在组内服务 | — |
RECOVERING | 正在补数据,还没进组 | 恢复通道账号/权限不对,或数据量大在正常追(看 replication_group_member_stats 的进度) |
UNREACHABLE | 其他节点认为它失联 | 组通信端口不通 / 网络抖动 |
ERROR | 已被踢出组 | 数据分叉、执行了组不允许的操作(如无主键表写入) |
写入能力确认(单主模式下 SECONDARY 应当是只读的):
SELECT @@super_read_only; -- PRIMARY 返回 0,SECONDARY 返回 1
单主模式下确认谁是主:
SELECT MEMBER_HOST FROM performance_schema.replication_group_members
WHERE MEMBER_ROLE = 'PRIMARY';
2
# 坑与边界
- 组通信端口(
group_replication_local_address里那个)必须单独放行,它和 MySQL 端口是两回事。只放行 3306 会让节点卡在RECOVERING,是新搭 MGR 最高频的问题。 group_replication_start_on_boot = off是刻意的。开成 on 之后,节点重启会自动尝试加入组;如果它重启前有未同步出去的事务,自动加入会导致数据分叉直接进ERROR状态。保持 off,重启后人工确认再START GROUP_REPLICATION。- 多主模式(
single_primary_mode = 0)不是「性能更好的单主」。它要求enforce_update_everywhere_checks = ON,代价是:不支持外键级联、不支持SERIALIZABLE、同一行的并发更新会在提交时被认证阶段直接回滚(乐观并发)。没有明确的多点写入需求就用单主。 - 两种模式不能混:组内所有节点的
single_primary_mode和enforce_update_everywhere_checks必须完全一致,不一致的节点会被拒绝加入。本文上面给的单主/多主两份配置是二选一,不是拼在一起用。 - 多数派是硬约束:3 节点挂 2 个后,剩下的那个不会自动接管,整组不可写(
ERROR 3101)。这是设计如此。确认另外两个确实回不来时才用group_replication_force_members强制重组——有脑裂风险,属最后手段。 - 大事务会被直接拒绝:
group_replication_transaction_size_limit(文中设的 331350016 ≈ 316MB,默认 150MB)超限的事务报错回滚。批量导数据前分批处理。 SET GLOBAL GTID_PURGED是危险操作,不要当成常规修复手段。它直接改写「哪些事务算已执行」,用错会让节点跳过真实存在的数据变更,造成静默的数据不一致。只在明确知道要跳过什么、且已确认数据差异可接受时使用——处置思路见 MySQL 基于 GTID 主从复制:跳过异常事务的正确姿势。
集群化纳管(MySQL Shell + Router)见 innodb cluster 安装。