环境:3 节点 MGR(192.168.195.141 / 142 / 143,均 CentOS 系 Kylin V10,2.8G 内存),MySQL 8.0.35 二进制包(官方归档源)
覆盖:MGR.pdf 全部内容 – 架构原理、部署(单主/多主)、全部管理操作(在线切换/手动切主/加减节点/clone 重建)、常见故障模拟与解决、监控、知识点补充
验证状态:12 个场景全部实测通过(单主 failover、多主并发写、冲突检测、脑裂防护、clone 重建、权重选举等)
所有命令注明执行节点,老板可按文档逐步复现。
一、MGR 架构原理(PDF 核心章节精要)
1.1 什么是 MGR
MySQL Group Replication:基于 Paxos 变种(XCom/Paxos 协议)实现的多写复制插件,提供自动故障检测、自动 failover、强一致性(多数派认证)。
三大特点(PDF 原文要点):
- 高可用:成员故障自动剔除/检测,单主模式自动选举新主(秒级)
- 强一致:事务经多数派(N/2+1)认证才提交,无数据丢失风险(RPO=0)
- 弹性:在线加减节点、在线单主<->多主模式切换
1.2 单主 vs 多主(PDF 对比)
| 维度 | 单主模式 (single-primary) | 多主模式 (multi-primary) |
|---|---|---|
| 写入点 | 仅 PRIMARY 一个(SECONDARY 全部 super_read_only) | 所有成员均可写 |
| 冲突 | 无(写冲突不可能发生) | 存在,靠认证机制检测回滚 |
| 二级制日志 | binlog + applier 并行 | 同左 |
| 适用 | 绝大多数业务(默认推荐) | 特殊多写需求/跨地域写 |
| 隔离级别 | 默认 REPEATABLE READ | 建议读已提交 + ROW 格式 |
| 性能 | 高(无认证开销集中) | 相对低(每个事务都认证) |
1.3 事务认证流程(PDF 认证章节)
客户端事务(本地BEGIN..UPDATE..COMMIT)
└─> 本地执行,产生 write set(XXHASH64 提取)
└─> 组播给所有成员(XCom/Paxos 全序广播)
├─> 各成员认证器(certifier)比对 write set:
│ 若与已认证事务的 write set 无冲突 → 认证通过
│ 冲突 → 后到者回滚(客户端收到 ERROR)
└─> 多数派(N/2+1)达成一致 → 提交
└─> 各成员 applier 异步应用(relay log → binlog)
冲突检测本质:比对事务修改行的主键 write set。两个并发事务改同一行,先认证者胜出,后到者在所有成员上被回滚(包括发起者)。
1.4 多数派与脑裂防护
- 3 节点组:需 2 台存活(多数派)才能对外服务
- 网络分区时少数派无法达成多数派认证,事务无法提交(卡住直至超时),不会脑裂写数据
group_replication_unreachable_majority_timeout:少数派超时退出组(默认 0 不退出),生产建议设置
二、架构规划(本环境)
MGR 集群(单主起步,后续在线切多主):
192.168.195.141 server-id=1 初始引导为 PRIMARY
192.168.195.142 server-id=2 SECONDARY
192.168.195.143 server-id=3 SECONDARY
组通信端口: 33061 (每节点的 group_replication_local_address)
MySQL 服务端口: 3306
组名(UUID): 982e833d-9c5e-4bcb-a36a-d05573d03bb8 (uuidgen 生成,三节点必须一致)
为什么这样规划:3 节点是 MGR 最小高可用单元(容忍 1 台故障);单主模式是生产默认;组通信端口独立于 3306 便于防火墙策略。
三、环境清理(三节点执行)
清理旧 MySQL / Orchestrator / MHA / Docker / VIP 残留:
# 执行节点: 141/142/143 分别执行
ip addr del 192.168.195.200/24 dev ens32 2>/dev/null
systemctl stop mysqld orchestrator orch-smtp 2>/dev/null
systemctl disable mysqld orchestrator orch-smtp 2>/dev/null
rm -rf /etc/systemd/system/mysqld.service /etc/systemd/system/orchestrator.service \
/etc/systemd/system/orch-smtp.service /data/mysql /etc/my.cnf /etc/my3307.cnf \
/etc/sysconfig/mysql /home/orchestrator /var/lib/orchestrator /var/log/orchestrator \
/var/mailbox /opt/smtp_server.py /etc/profile.d/orchestrator-client.sh \
/etc/masterha /var/log/masterha /usr/local/bin/orchestrator-client /usr/local/bin/masterha*
rpm -e mha4mysql-node mha4mysql-manager 2>/dev/null
rm -rf /usr/local/mysql /usr/local/mysql-8.0.35-linux-glibc2.17-x86_64
userdel -r mysql 2>/dev/null; userdel -r orchestrator 2>/dev/null
systemctl daemon-reload
# 验证: 无 mysqld/orchestrator 进程, /usr/local/mysql 不存在, id mysql 报无此用户
四、MySQL 8.0.35 安装(三节点)
4.1 下载(官方归档源,国内镜像无 8.0.35)
# 执行节点: 141(下载后 scp 分发)
cd /usr/local/src
curl -sL -o mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz \
"https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz"
md5sum mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz
# c17075cfc58d8cd25cea4be36d77eed2 (三节点必须一致)
scp mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz root@192.168.195.142:/usr/local/src/
scp mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz root@192.168.195.143:/usr/local/src/
国内源尝试记录:清华 tuna / 阿里 / 腾讯 / 华为 / 中科大镜像的 MySQL-8.0 目录均只到 8.0.28(glibc2.17 完整包),无 8.0.35,故用官方归档源(可达,419MB,速度快)。
4.2 用户与解压(三节点)
# 执行节点: 141/142/143
groupadd -f mysql && useradd -g mysql -s /sbin/nologin mysql
cd /usr/local && tar xf /usr/local/src/mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz
ln -sf mysql-8.0.35-linux-glibc2.17-x86_64 mysql
mkdir -p /data/mysql/3306/data && chown -R mysql:mysql /data/mysql
/usr/local/mysql/bin/mysql --version # Ver 8.0.35
4.3 my.cnf(MGR 核心,三节点仅 server-id/report_host/local_address 不同)
# 执行节点: 141(142/143 把 server-id 改为 2/3, IP 尾段对应改)
cat > /etc/my.cnf << 'EOF'
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
# ===== 基础复制参数 =====
server-id = 1 # 三节点唯一(1/2/3)
log-bin = mysql-bin # MGR 强制 binlog
binlog_format = ROW # MGR 强制 ROW
binlog_row_image = FULL # MGR 强制 FULL(8.0 默认)
gtid_mode = ON # MGR 强制 GTID
enforce_gtid_consistency = ON
log_slave_updates = ON # 组内事务要写回 binlog
master_info_repository = TABLE # 崩溃安全(8.0 默认TABLE)
relay_log_info_repository = TABLE
relay_log_recovery = ON
report_host = 192.168.195.141 # 组内显示的主机名(关键!否则用主机名解析)
report_port = 3306
# ===== MGR 核心参数 =====
# loose- 前缀: 插件未安装时参数不报错,mysqld 可先正常启动
loose-plugin_load_add = 'group_replication.so' # 随服务自动加载 MGR 插件
loose-transaction_write_set_extraction = XXHASH64 # write set 提取算法(冲突检测用)
loose-group_replication_group_name = '982e833d-9c5e-4bcb-a36a-d05573d03bb8' # 组名,三节点一致
loose-group_replication_start_on_boot = OFF # 不随 mysqld 自动启动组(手动控制,便于演练)
loose-group_replication_local_address = '192.168.195.141:33061' # 本节点组通信地址
loose-group_replication_group_seeds = '192.168.195.141:33061,192.168.195.142:33061,192.168.195.143:33061'
loose-group_replication_bootstrap_group = OFF # 引导开关,仅首次手动置 ON
loose-group_replication_single_primary_mode = ON # 单主模式(生产默认)
loose-group_replication_recovery_use_ssl = 0 # 恢复通道不走SSL(实验环境)
# ===== MGR 性能/容错调优 =====
loose-group_replication_communication_stack = XCOM # 8.0.27+ 通信栈
loose-group_replication_message_cache_size = 1073741824 # 消息缓存 1G(恢复时补偿用)
# loose-group_cache_size = 134217728 # 8.0.26+ 已并入 message_cache_size,注释保留
loose-group_replication_flow_control_mode = 'DISABLED' # 流控关闭(小集群/低延迟内网)
loose-group_replication_poll_spin_loops = 72 # 通信轮询自旋(默认)
loose-group_replication_compression_threshold = 1000000 # 组播消息压缩阈值 1M
loose-group_replication_exit_state_action = READ_ONLY # 异常退出时自动只读(安全)
loose-group_replication_member_expel_timeout = 5 # 成员驱逐超时(默认5s,可调大容忍抖动)
# ===== 内存参数(2.8G 小内存机器) =====
innodb_buffer_pool_size = 512M
innodb_redo_log_capacity = 256M
EOF
⚠️ 避坑:
group_replication_group_seeds必须包含全部节点(含自己);report_host强烈建议写 IP,避免主机名解析问题。
4.4 systemd 服务 + 初始化(三节点)
# 执行节点: 141/142/143
cat > /etc/systemd/system/mysqld.service << 'EOF'
[Unit]
Description=MySQL Server (MGR Node)
After=network.target syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
Type=forking
PIDFile=/data/mysql/3306/data/mysqld.pid
TimeoutSec=0
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --pid-file=/data/mysql/3306/data/mysqld.pid --daemonize $MYSQLD_OPTS
EnvironmentFile=-/etc/sysconfig/mysql
LimitNOFILE=65535
Restart=on-failure
RestartPreventExitStatus=1
PrivateTmp=false
EOF
echo 'MYSQLD_OPTS=' > /etc/sysconfig/mysql
systemctl daemon-reload
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --initialize # 无输出即成功
grep 'temporary password' /data/mysql/3306/data/mysqld.err # 取临时密码
systemctl start mysqld && systemctl enable mysqld
4.5 改密码 + 安装插件(三节点)
-- 执行节点: 141/142/143 (用各自的临时密码登录)
ALTER USER user() IDENTIFIED BY 'Root@123456';
INSTALL PLUGIN group_replication SONAME 'group_replication.so'; -- MGR插件
INSTALL PLUGIN clone SONAME 'mysql_clone.so'; -- clone插件(增量重建用)
SHOW PLUGINS; -- 两行 ACTIVE 即成功:
-- group_replication ACTIVE GROUP REPLICATION group_replication.so GPL
-- clone ACTIVE CLONE mysql_clone.so GPL
4.6 复制用户(三节点,SQL_LOG_BIN=0 防止本地事务污染 GTID)
-- 执行节点: 141/142/143
SET SQL_LOG_BIN=0; -- 关键!建用户不记 binlog,避免各节点 GTID 不一致
CREATE USER 'repuser'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repuser'@'%';
CREATE USER 'repuser'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repuser'@'127.0.0.1';
CREATE USER 'repuser'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repuser'@'localhost';
SET SQL_LOG_BIN=1;
-- 配置组恢复通道(新节点加入时经此通道从种子节点补数据)
CHANGE MASTER TO MASTER_USER='repuser', MASTER_PASSWORD='123456'
FOR CHANNEL 'group_replication_recovery';
五、单主 MGR 组启动(首次引导)
5.1 141 引导组(仅首次!)
-- 执行节点: 141
SET GLOBAL group_replication_bootstrap_group=ON; -- 打开引导开关
START GROUP_REPLICATION; -- 启动组(此刻组里只有自己)
SET GLOBAL group_replication_bootstrap_group=OFF; -- 立刻关闭!否则重启会分裂成两个组
-- 验证(几秒后):
SELECT MEMBER_HOST, MEMBER_ROLE, MEMBER_STATE FROM performance_schema.replication_group_members;
-- MEMBER_HOST MEMBER_ROLE MEMBER_STATE
-- 192.168.195.141 PRIMARY ONLINE <- 引导成功
5.2 142/143 加入组
-- 执行节点: 142(143 同理)
START GROUP_REPLICATION;
-- 若报 ERROR 3092 + 错误日志有 "This member has more executed transactions than those
-- present in the group" -> 节点有本地事务(如装插件时记了 binlog),与组 GTID 冲突。
-- 解决(新节点安全操作): 清空本地 GTID 再加入
STOP GROUP_REPLICATION;
RESET MASTER; -- 清空 gtid_executed 与 binlog(仅对全新节点安全!)
START GROUP_REPLICATION;
5.3 全组上线验证
-- 执行节点: 任意成员
SELECT MEMBER_HOST, MEMBER_ROLE, MEMBER_STATE, MEMBER_VERSION
FROM performance_schema.replication_group_members;
-- 192.168.195.141 PRIMARY ONLINE 8.0.35
-- 192.168.195.142 SECONDARY ONLINE 8.0.35
-- 192.168.195.143 SECONDARY ONLINE 8.0.35 <- 三节点全 ONLINE 即成功
-- 从节点自动进入只读:
SELECT @@read_only, @@super_read_only; -- 142/143 应为 1/1
5.4 测试数据(主库建,秒级同步)
-- 执行节点: 141 (PRIMARY)
CREATE DATABASE mgr_test;
USE mgr_test;
CREATE TABLE t1 (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
amount DECIMAL(10,2) DEFAULT 0.00,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
INSERT INTO t1(name,amount) VALUES ('订单A',100.00),('订单B',200.50),('订单C',300.75);
CREATE TABLE t2 (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
host_tag VARCHAR(20),
note VARCHAR(100)
) ENGINE=InnoDB;
INSERT INTO t2(host_tag,note) VALUES ('node141-init','初始数据'),('node141-init','第二条');
-- 执行节点: 142/143 验证(应秒级一致):
SELECT COUNT(*) FROM mgr_test.t1; -- 3
SELECT COUNT(*) FROM mgr_test.t2; -- 2
5.5 单主写限制验证
-- 执行节点: 142/143 (SECONDARY)
INSERT INTO mgr_test.t1(name) VALUES ('try-write');
-- ERROR 1290 (HY000): The MySQL server is running with the
-- --super-read-only option so it cannot execute this statement
-- <- 报此错 = 单主模式只读保护生效,验证成功
六、全场景验证实录(12 场景全部通过)
场景1: PRIMARY 故障自动 failover ✅
# 执行节点: 141 (当时 PRIMARY)
systemctl stop mysqld # 模拟主库宕机
-- 执行节点: 142 (约10~30秒后查询,组检测+选举)
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 实测结果:
-- 192.168.195.142 PRIMARY ONLINE <- 142 自动当选新主
-- 192.168.195.143 SECONDARY ONLINE
-- 新主写入验证(业务无缝):
-- 执行节点: 142
INSERT INTO mgr_test.t1(name,amount) VALUES ('write-on-new-primary',888.88);
SELECT COUNT(*) FROM mgr_test.t1; -- 4 (含旧主已同步的全部数据,零丢失)
SELECT @@read_only; -- 0 (新主可写)
恢复旧主回组(重要:旧主重启后是独立实例,需手动加入):
# 执行节点: 141
systemctl start mysqld
START GROUP_REPLICATION; -- 141 以 SECONDARY 回归,自动追平差量
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 141 SECONDARY ONLINE,数据自动同步到最新
场景2: 手动在线切主(group_replication_set_as_primary)✅
-- 执行节点: 当前 PRIMARY (任意成员执行,组内广播)
-- 1.查目标成员 UUID:
SELECT MEMBER_ID FROM performance_schema.replication_group_members
WHERE MEMBER_HOST='192.168.195.141';
-- -> a2c03766-98c0-11f1-8e59-000c29048d1f
-- 2.指定切主:
SELECT group_replication_set_as_primary('a2c03766-98c0-11f1-8e59-000c29048d1f');
-- -> Primary server switched to: a2c03766-... (切换成功)
-- 3.验证:
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 141 -> PRIMARY, 其余 SECONDARY, 全 ONLINE
场景3: 单主 -> 多主在线切换 ✅
-- 执行节点: 任意成员
SELECT group_replication_switch_to_multi_primary_mode();
-- -> Mode switched to multi-primary successfully.
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 实测: 三个节点全部 PRIMARY, 全 ONLINE
多主三节点并发写验证(数据最终一致):
-- 执行节点: 141
INSERT INTO mgr_test.t1(name,amount) VALUES ('multi-141',11.11);
-- 执行节点: 142
INSERT INTO mgr_test.t1(name,amount) VALUES ('multi-142',22.22);
-- 执行节点: 143
INSERT INTO mgr_test.t1(name,amount) VALUES ('multi-143',33.33);
-- 三节点分别验证(最终完全一致):
SELECT COUNT(*) rows_all, SUM(amount) total FROM mgr_test.t1;
-- 三节点均为: rows_all=7, total=1556.79 <- 一致性验证成功
场景4: 多主写冲突检测(certification)✅
# 双端同时 INSERT 相同主键(并发脚本):
# 执行节点: 142 后台脚本
cat > /tmp/ins142.sh << "EOF"
#!/bin/bash
M="/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock -pRoot@123456 mgr_test"
sleep 5 # 等双端就绪,同时开跑
$M -e "INSERT INTO race_t VALUES (8888,\"from142\",NOW(3));"
EOF
# 执行节点: 143 同样脚本(值 from143)
-- 实测结果:
-- 142: 插入成功(先通过组认证)
-- 143: ERROR 1062 (23000): Duplicate entry '8888' for key 'race_t.PRIMARY'
-- <- 后到者在认证阶段被回滚,客户端收到错误。这就是 MGR 冲突检测!
-- 最终全组一致(只有一条 8888):
SELECT id,src FROM mgr_test.race_t WHERE id=8888; -- from142
-- 认证统计(PDF 监控点):
SELECT COUNT_TRANSACTIONS_CHECKED FROM performance_schema.replication_group_member_stats;
-- 数值持续增长 = 认证器在工作
知识点:冲突在组认证阶段检测(基于 write set 的主键/唯一键比对),后提交者在所有成员上回滚。业务侧应靠"不同节点写不同分片/表"规避冲突,而非依赖回滚。
场景5: 多主模式删节点(STOP GROUP_REPLICATION)✅
-- 执行节点: 143 (主动退出组)
STOP GROUP_REPLICATION;
-- 组内其余成员视角: 143 消失,141/142 继续服务
-- 143 数据停在退出前(502行),后续组内新写不会同步给它
-- 重新加入(数据落后时需先补齐,见场景6):
START GROUP_REPLICATION;
场景6: clone 插件物理重建落后节点 ✅
适用:节点数据落后太多/数据目录损坏,用 clone 从 donor 物理拷贝重建(比 binlog 追平快得多)。
-- 第1步: donor(141) 建 clone 账号
-- 执行节点: 141
SET SQL_LOG_BIN=0;
CREATE USER 'clone_user'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT BACKUP_ADMIN ON *.* TO 'clone_user'@'%'; -- donor 必须 BACKUP_ADMIN
SET SQL_LOG_BIN=1;
-- 第2步: recipient(143) 执行克隆
-- 执行节点: 143
STOP GROUP_REPLICATION; -- 先退出组
SET GLOBAL super_read_only=0; -- 克隆需要可写(clone报1290时)
SET GLOBAL clone_valid_donor_list = '192.168.195.141:3306'; -- 指定donor白名单
CLONE INSTANCE FROM 'clone_user'@'192.168.195.141':3306 IDENTIFIED BY '123456';
-- 报 ERROR 3707 (Restart server failed) 是正常现象:clone完成后实例自动重启,
-- systemd 管理下 supervisor 不在,需手动: systemctl start mysqld
# 执行节点: 143
systemctl start mysqld # 完成克隆收尾
-- 验证克隆结果(数据与 donor 完全一致):
SELECT COUNT(*) FROM mgr_test.race_t; -- 502 (与141一致)
SELECT COUNT(*) FROM mgr_test.t1; -- 7
-- 重新入组:
START GROUP_REPLICATION;
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 三节点全 ONLINE
clone 踩坑实录(都写进文档供参考):
Access denied; you need BACKUP_ADMIN-> donor 的 clone 账号缺 BACKUP_ADMIN 权限ERROR 1290 --super-read-only-> recipient 处于只读,先SET GLOBAL super_read_only=0ERROR 3707 Restart server failed (mysqld is not managed by supervisor process)-> systemd 管理的实例克隆后不会自动重启,systemctl start mysqld即可
场景7: 多主 -> 单主回切 ✅
-- 执行节点: 任意成员(8.0.13+ 不允许 SET GLOBAL 改模式,必须用UDF)
-- 先取目标主 UUID:
SELECT MEMBER_ID FROM performance_schema.replication_group_members
WHERE MEMBER_HOST='192.168.195.141';
SELECT group_replication_switch_to_single_primary_mode('a2c03766-98c0-11f1-8e59-000c29048d1f');
-- -> Mode switched to single-primary successfully.
-- 实测: 直接 SET GLOBAL group_replication_single_primary_mode=ON 会报:
-- ERROR 3093: Cannot modify group replication mode by changing
-- group_replication_single_primary_mode system variable.
-- Please use the group_replication_switch_to_single_primary_mode() UDF
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 141 PRIMARY, 142/143 SECONDARY, 全 ONLINE
场景8: 选举权重(group_replication_member_weight)✅
-- 执行节点: 143(设为最高权重,期望它当选新主)
SET GLOBAL group_replication_member_weight=100;
-- 执行节点: 142
SET GLOBAL group_replication_member_weight=50;
-- (141保持默认0; 权重只在选举时比较,越大越优先当选)
# 执行节点: 141(当前PRIMARY) 模拟宕机
systemctl stop mysqld
-- 执行节点: 142 视角(约30秒后):
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 实测: 143(weight=100) 当选 PRIMARY, 142(weight=50) 仍 SECONDARY
-- <- 权重选举生效,验证成功!
权重是选举建议而非绝对:若高权重节点数据落后(未追平),组仍会选数据最全的成员,防丢数据优先。
场景9: 网络分区/脑裂防护(多数派 vs 少数派)✅
# 执行节点: 143(当时PRIMARY) 用 iptables 隔离自己的组通信端口
iptables -A INPUT -p tcp --dport 33061 -j DROP
iptables -A OUTPUT -p tcp --dport 33061 -j DROP
-- 约40秒后,多数派(141+142)视角:
-- 执行节点: 141
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 实测: 141 自动当选新 PRIMARY,143 被踢出视图(141/142 ONLINE)
-- 少数派(143)视角(脑裂现场!):
-- 执行节点: 143
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 141/142 显示 UNREACHABLE,143 仍自认 PRIMARY,@@read_only=0
-- 关键验证: 少数派写入无法提交!
-- 执行节点: 143
INSERT INTO mgr_test.t1(name) VALUES ('minority-write');
-- 实测: 语句卡住(等多数派认证,永不可能达成),超时被杀后事务仍在 RUNNING:
SELECT trx_state FROM information_schema.innodb_trx; -- RUNNING(悬挂)
-- <- 这就是 MGR 脑裂防护: 少数派"看似主库"但写不进任何数据
# 解除隔离(执行节点: 143)
iptables -D INPUT -p tcp --dport 33061 -j DROP
iptables -D OUTPUT -p tcp --dport 33061 -j DROP
-- 约30秒后自动收敛(无需人工干预):
-- 执行节点: 143
SELECT MEMBER_HOST,MEMBER_ROLE,MEMBER_STATE FROM performance_schema.replication_group_members;
-- 实测: 143 自动降级 SECONDARY(read_only=1),数据自动追平(8行与多数派一致)
-- 少数派期间的悬挂事务被回滚,零数据分裂 <- 自愈完整闭环!
场景10: flow control 流控与监控视图 ✅
-- 执行节点: 141
SHOW VARIABLES LIKE 'group_replication_flow_control%';
-- 关键参数:
-- flow_control_mode = DISABLED (本环境关闭;生产默认ADAPTIVE)
-- flow_control_applier_threshold = 25000 (applier队列超此值触发流控)
-- flow_control_certifier_threshold = 25000(认证队列阈值)
-- flow_control_hold_percent/release_percent: 流控时暂停/恢复的吞吐比例
-- 成员事务统计(核心监控表):
SELECT MEMBER_ID,
COUNT_TRANSACTIONS_IN_QUEUE, -- 认证队列(积压告警点)
COUNT_TRANSACTIONS_CHECKED, -- 已认证事务数
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE, -- 远程applier积压(延迟告警点)
COUNT_TRANSACTIONS_REMOTE_APPLIED -- 已应用远程事务
FROM performance_schema.replication_group_member_stats;
场景11: 从库网络闪断自愈 ✅
# 执行节点: 142 (SECONDARY) 隔离30秒再恢复
iptables -A INPUT -p tcp --dport 33061 -j DROP
iptables -A OUTPUT -p tcp --dport 33061 -j DROP
sleep 35
iptables -D INPUT -p tcp --dport 33061 -j DROP
iptables -D OUTPUT -p tcp --dport 33061 -j DROP
-- 实测时间线:
-- T+35s: 141视角 142 被踢出(只剩141/143,多数派仍存活,服务不中断)
-- T+65s: 142 网络恢复后自动重连回组,SECONDARY ONLINE,数据自动追平(8行)
-- 全程主库服务不中断,无需人工干预 <- MGR 健壮性实证
场景12: 全组 GTID 一致性核验 ✅
-- 执行节点: 141/142/143 分别执行,比对输出必须完全一致
SELECT @@gtid_executed;
-- 实测三节点输出:
-- 982e833d-9c5e-4bcb-a36a-d05573d03bb8:1-20:1000006-1000543:2000007-2000040,
-- a2c03766-98c0-11f1-8e59-000c29048d1f:1
-- (含多主阶段历史 + VIEW变更事件,三节点逐字节一致 = 组一致性健康)
七、日常管理命令速查(MGR 运维必背)
7.1 组状态监控
-- 成员视图(最常用,健康检查第一入口)
SELECT MEMBER_HOST, MEMBER_ROLE, MEMBER_STATE, MEMBER_VERSION
FROM performance_schema.replication_group_members;
-- 成员事务统计
SELECT * FROM performance_schema.replication_group_member_stats\G
-- 组通信信息(视图ID/所有权)
SELECT * FROM performance_schema.replication_group_communication_information\G
-- 连接状态(恢复通道/applier通道)
SELECT * FROM performance_schema.replication_connection_status
WHERE CHANNEL_NAME LIKE 'group%';
SELECT * FROM performance_schema.replication_applier_status
WHERE CHANNEL_NAME LIKE 'group%';
7.2 成员管理
START GROUP_REPLICATION; -- 加入组
STOP GROUP_REPLICATION; -- 退出组(数据保留)
SET GLOBAL group_replication_bootstrap_group=ON; -- 引导组(仅首次,用完立即OFF)
7.3 模式切换(8.0.13+ UDF)
SELECT group_replication_switch_to_multi_primary_mode(); -- 单主->多主
SELECT group_replication_switch_to_single_primary_mode(); -- 多主->单主(自动选主)
SELECT group_replication_switch_to_single_primary_mode('uuid'); -- 多主->单主(指定主)
SELECT group_replication_set_as_primary('uuid'); -- 单主下手动指定切主
⚠️ 8.0.13 起禁止
SET GLOBAL group_replication_single_primary_mode直接改(ERROR 3093),必须用 UDF 在线切换。
7.4 MGR 相关重要变量
SHOW VARIABLES LIKE 'group_replication%';
-- 选举与超时:
-- group_replication_member_weight 选举权重(越大越优先当选)
-- group_replication_member_expel_timeout 驱逐超时(默认5s)
-- group_replication_unreachable_majority_timeout 少数派超时退出(默认0不退,生产建议设)
-- group_replication_exit_state_action 异常退出动作(READ_ONLY/ABORT_SERVER)
-- 流控:
-- group_replication_flow_control_mode DISABLED/ADAPTIVE(生产默认)
-- 恢复:
-- group_replication_recovery_use_ssl 恢复通道SSL
-- clone_valid_donor_list clone donor白名单
八、常见故障与排错(实测踩坑汇总)
8.1 新节点加入报 ERROR 3092(本地 GTID 多于组)
ERROR 3092: The server is not configured properly to be an active member of the group.
错误日志: This member has more executed transactions than those present in the group.
原因:新节点有本地事务(装插件/建用户时未 SET SQL_LOG_BIN=0,记入了 binlog),组拒绝接纳来路不明的事务。
解决(全新节点安全):STOP GROUP_REPLICATION; RESET MASTER; START GROUP_REPLICATION;
预防:所有"管理性质"SQL(建用户/授权/装插件)前先 SET SQL_LOG_BIN=0。
8.2 clone 报权限/只读错误
| 报错 | 原因 | 解决 |
|---|---|---|
Access denied; BACKUP_ADMIN | donor 端 clone 账号缺权 | donor: GRANT BACKUP_ADMIN ON *.* TO clone_user |
ERROR 1290 super-read-only | recipient 处于只读 | recipient: SET GLOBAL super_read_only=0 |
ERROR 3707 Restart failed | systemd 下无 supervisor | systemctl start mysqld 手动拉起 |
8.3 ERROR 3093 模式切换被拒
ERROR 3093: Cannot modify group replication mode by changing
group_replication_single_primary_mode system variable.
原因:8.0.13+ 禁止 SET GLOBAL 改模式。
解决:用 UDF(见 7.3)。
8.4 成员长时间 UNREACHABLE
排查:group_replication_local_address 端口(默认33061)网络连通性;member_expel_timeout 是否设得过大;对端 mysqld 存活。
处置:网络恢复后组自动收敛(场景9/11 实证);若节点确定报废,多数派继续服务,节点用 clone 重建(场景6)。
8.5 少数派悬挂事务
现象:分区期间少数派的写事务卡 RUNNING 不返回。
原理:事务需多数派认证,分区下不可能达成,只能等超时或分区恢复。
预防:设 group_replication_unreachable_majority_timeout(如30s),少数派主动退出组转只读,客户端快速失败重定向到多数派 VIP。
九、部署检查清单(复现路线图)
| 步骤 | 操作 | 节点 | 验证点 |
|---|---|---|---|
| 1 | 清理旧环境 | 三节点 | 无 mysqld 服务/进程/目录 |
| 2 | 下载+分发二进制包 | 141->全 | md5 一致 (c17075cfc58d8cd25cea4be36d77eed2) |
| 3 | 建用户/解压/软链 | 三节点 | mysql --version = 8.0.35 |
| 4 | 写 /etc/my.cnf | 三节点 | server-id 唯一,组名/seeds 一致 |
| 5 | systemd 服务+初始化 | 三节点 | 错误日志出现临时密码 |
| 6 | 改密+装两插件 | 三节点 | SHOW PLUGINS 两行 ACTIVE |
| 7 | repuser+恢复通道 | 三节点 | mysql.user 3 条 repuser |
| 8 | 141 引导组 | 141 | PRIMARY ONLINE |
| 9 | 142/143 加入 | 142/143 | (3092 则 RESET MASTER) 三节点全 ONLINE |
| 10 | 建测试库表 | 141 | 142/143 秒级同步 |
| 11 | 12 场景验证 | 按209章 | 全部通过 ✅ |
十、环境现状快照(2026-08-16 00:05)
集群模式: 单主 (141=PRIMARY, 142/143=SECONDARY, 全 ONLINE)
GTID: 三节点一致
测试库: mgr_test (t1=8行, t2=2行, race_t=503行, conflict_t=1行)
组名: 982e833d-9c5e-4bcb-a36a-d05573d03bb8
节点 UUID: 141=a2c03766-98c0-11f1-8e59-000c29048d1f
142=a416e0e7-98c0-11f1-8379-000c29a59955
143=a5681ae0-98c0-11f1-a06d-000c29c39241
选举权重: 143=100, 142=50, 141=0 (运行时SET,重启失效)
MySQL root 密码: Root@123456 (三节点)
repuser/clone_user 密码: 123456
本笔记所有命令均为实测执行,输出为真实回显。可按"部署检查清单"逐步复现完整环境。
PDF 未覆盖但生产必知:MGR 不处理"客户端如何找到新主"(需 VIP/ProxySQL/Router 配合,参考 MHA/Orchestrator 笔记同理)。

703

被折叠的 条评论
为什么被折叠?



