MGR 组复制

 

MGR 组复制搭建手册(MySQL/MariaDB)

本文介绍如何在多节点上搭建 MySQL/MariaDB 的 MGR 组复制(Group Replication),采用单主(single-primary)模式。覆盖:开启前置条件、数据准备(备份预灌 vs 增量恢复)、核心开启流程、验证与常见坑。GreatSQL / GreatDB 的特定差异见文末补充。

拓扑示例:3 个节点(host-a 为初始主库,host-b / host-c 为新增从库),组内节点通过专用端口互连。下文以 NODE_A:33061NODE_B:33061NODE_C:33061 示意,实际替换为各节点 IP。

一、前置条件(硬性,缺一不可)

1.1 基础参数:所有节点全部 ON

MGR 本质是基于 GTID 的复制,以下三个参数是运行前提,配置在 my.cnf 后需重启生效。集群中任一节点不满足都无法加入组。

-- 各节点分别确认:
SHOW VARIABLES WHERE Variable_name IN ('gtid_mode','enforce_gtid_consistency','log_slave_updates');
-- 期望三个值均为 ON

与 SET gtid_purged 的区别:这三个参数是「开启 GTID 机制」的开关,只保证"能用 GTID",不会让预灌/已恢复的数据自动带上 GTID 记录。数据一致性靠后文的 SET GLOBAL gtid_purged(见 §4.2)。两者缺一不可。

1.2 各节点 server_id 唯一

所有节点的 server_id 必须互不相同,否则组复制报错。

1.3 复制账号(含 BACKUP_ADMIN)

-- 各节点分别执行(用 IF NOT EXISTS 避免重复报错)
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '密码';
ALTER USER 'repl'@'%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '密码';
GRANT REPLICATION SLAVE, BACKUP_ADMIN ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

坑:若此前(如普通复制阶段)已建过同名账号,直接用 CREATE USER 会报 ERROR 1396 ... already exists 中断操作。务必用 CREATE USER IF NOT EXISTS 或改为 ALTER USER+GRANT

1.4 组复制插件(必须)+ clone 插件(可选)

-- 各节点确认:group_replication 必须 ACTIVE
SHOW PLUGINS; | grep group_replication

-- clone 插件可选(见下方说明),非必需
SHOW PLUGINS; | grep clone

group_replication 为组复制本体,必须处于 ACTIVE。clone 插件非必需——它只在「加入节点与组数据不一致、需要从 donor 全量克隆补齐」时才用到;若数据已通过备份预灌一致(见 §3 方式 A),用增量恢复即可,完全不需要 clone。因此 clone 仅作为可选/兜底手段。

1.5 端口互通

  • MGR 专用端口(如 33061):组内节点 group communication 互连,所有节点互相放通;
  • MySQL 业务/复制端口(如 3306):节点间互通。

1.6 内存核定(关键校验)

致命坑:innodb_buffer_pool_size 必须按各节点自身物理内存核定(一般建议 ≤70%),并预留 OS、性能库、恢复进程的内存余量。若某节点内存偏小而照搬大节点的 buffer pool,该节点可能 起不来或 OOM。上线前先确认每台服务器物理内存,再分别设置。

1.7 my.cnf MGR 参数段(各节点追加,group_name / group_seeds 全局一致)

# MGR(追加到 [mysqld] 段)
loose-plugin_load_add = 'group_replication.so'
loose-group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa1"   # ⚠占位符,上线前换真实UUID
loose-group_replication_local_address = "NODE_A_IP:33061"     # 各节点填自己的IP
loose-group_replication_group_seeds = "NODE_A_IP:33061,NODE_B_IP:33061,NODE_C_IP:33061"
loose-group_replication_communication_stack = "XCOM"
loose-group_replication_recovery_use_ssl = OFF
loose-group_replication_ssl_mode = DISABLED
loose-group_replication_start_on_boot = OFF
loose-group_replication_bootstrap_group = OFF
loose-group_replication_exit_state_action = READ_ONLY
loose-group_replication_flow_control_mode = "DISABLED"
loose-group_replication_single_primary_mode = ON
loose-group_replication_enforce_update_everywhere_checks = OFF
loose-group_replication_majority_after_mode = ON
loose-group_replication_communication_max_message_size = 10M
loose-group_replication_arbitrator = OFF
loose-group_replication_single_primary_fast_mode = 1
loose-group_replication_request_time_threshold = 100
loose-group_replication_primary_election_mode = GTID_FIRST
loose-group_replication_unreachable_majority_timeout = 0
loose-group_replication_member_expel_timeout = 5
loose-group_replication_autorejoin_tries = 288
loose-group_replication_recovery_get_public_key = ON
loose-group_replication_donor_threshold = 100

坑:group_name 是占位符,上线前必须换成真实随机 UUID,且所有节点保持一致;② member_expel_timeout=5 偏激进,网络抖动可能误踢节点,生产建议放宽到 10~20;③ 改参数后需 systemctl restart 重启实例生效(服务名按实际 systemd 单元,如 mysql/mysqld)。

二、节点安装与初始化(MySQL/MariaDB)

MGR 组复制要求 MySQL 8.0.x(或兼容发行版)或 MariaDB 支持组复制的版本。全新节点需安装并初始化数据库服务;若某节点已有数据(如既有主库),则跳过初始化,直接保留其数据作为组内 PRIMARY 起点。

# MySQL 8.0:初始化数据目录 + 启动(以通用 my.cnf 配置为准,详见文末 GreatSQL 差异)
mysqld --initialize-insecure --user=mysql
systemctl start mysql            # 或 mysqld,按安装方式
mysql -uroot -e "SELECT VERSION();"

MGR 各节点用同一版本、同一 MGR 参数配置,确保组内兼容。节点数据不一致的处理见第三节。

三、数据准备与恢复

两种方式把既有数据带进新节点:A. 备份预灌(快,适合大库)或 B. 靠 MGR 增量/克隆恢复(慢,数据全从 PRIMARY 拉)。本文以 A 备份预灌为主,并说明配套的 GTID 一致性步骤。

3.1 从现有主库备份

# 从现有数据源用 mydumper 导出(示例:连源端)
mkdir -p /data/dbbak/$(date +%Y%m%d)
nohup /usr/bin/mydumper -u root -p '密码' -h 源IP --less-locking \
  --threads=8 -s 10000000 --chunk-filesize=1024 \
  --outputdir=/data/dbbak/$(date +%Y%m%d) --compress=1 --ignore-sysdb=1 --verbose=3 \
  >> /tmp/backup.log 2>&1 &

3.2 记录完整 GTID 集合(MGR 一致性关键,勿漏)

# 在数据源(将作为 PRIMARY 的节点)执行一次,记下输出填 §4.2 的 <GTID>
mysql --login-path=default-root -N -e "SELECT @@GLOBAL.gtid_executed;"
# 形如:b3d0abcd-xxxx-xxxx-xxxx-xxxxxxxxxxxx:1-NNNNN

关于备份的 metadata:mydumper 的 metadata 只稳记 Log:/Pos:(供普通复制位点用);是否含 GTID 字段(Executed_Gtid_Set)取决于版本,不可依赖。最稳就是上面这条 SELECT @@GLOBAL.gtid_executed。可核对:grep -i gtid /data/dbbak/<日期>/metadata

3.3 新节点恢复数据(myloader)

nohup /usr/bin/myloader -u root -p '' -S mysql.sock \
  --threads=8 --directory=/data/dbbak/$(date +%Y%m%d) \
  --verbose=3 --overwrite-tables >> /tmp/restore.log 2>&1 &

不加 -e:恢复事务不进 binlog,节点不记录恢复事务——这正是为什么它的 GTID 记录为空、必须靠 §4.2 手动 SET gtid_purged 补齐。若还要再挂级联从库才加 -e

四、开启组复制(核心流程)

4.1 各节点加载 MGR 参数并重启

systemctl restart mysql            # 服务名按实际(如 mysqld/mariadb)
mysql -uroot -e "SHOW PLUGINS;" | grep group_replication   # 必须 ACTIVE(clone 可选,见 §1.4)
# 再次确认各节点三参数 ON(§1.1)

4.2 各节点建账号 + 清理(注意 PRIMARY 禁止 RESET MASTER)

-- 各节点:建/改 repl 账号(见 §1.3)

-- 新节点(从库角色):清理残留,并补齐完整 GTID
RESET MASTER;
RESET SLAVE ALL;
SET GLOBAL gtid_purged = '<GTID>';   # <GTID>=§3.2 记下的完整GTID;声明"历史已恢复",加入组才只拉增量、不重放已灌数据

-- PRIMARY(有数据的节点):禁止 RESET MASTER / RESET SLAVE ALL(会清空 binlog 与 GTID),直接配 recovery 通道

-- 各节点:配置 recovery 通道
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='密码' FOR CHANNEL 'group_replication_recovery';

为什么必须有 SET gtid_purged:预灌的数据是直接装载的,新节点 gtid_purged 为空、gtid_executed 最多只有增量,缺失数据源完整历史。不 SET 的话,加入组时组会判定该节点缺全部历史,由 donor 整段重放 → 撞上已存在数据(表已存在/主键重复)→ recovery 失败、节点永远无法 ONLINE。SET 后声明"历史已有",加入时只拉增量。

4.3 引导并加入集群

-- 步骤①:在初始节点(将成为 PRIMARY)引导集群
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

-- 步骤②:其余节点加入
START GROUP_REPLICATION;

引导顺序固定:先 PRIMARY 再其他节点。建议先只加入一个从库、验证 ONLINE 并追平后再加第三个,避免一次全加难定位。bootstrap_group=ON 用完必须置回 OFF,防止误重启重复引导产生脑裂(多主脑裂)。

4.4 兜底/回滚

若组复制搭建失败:a) 先查 33061 端口连通性与 repl 账号权限;b) 必要时清理该节点状态后重新 START GROUP_REPLICATION;c) 若坚持普通复制兜底,需从干净状态重新装载数据并重建复制(不要在未清理 GTID/relay 的情况下与组复制混用)。

五、验证

SELECT * FROM performance_schema.replication_group_members;
-- 期望:各节点 MEMBER_STATE 均 ONLINE,PRIMARY 一个,其余 SECONDARY

SELECT * FROM performance_schema.replication_group_member_stats\G
-- 期望:各节点事务数一致(已追平)

-- 读写验证(单主下仅在 PRIMARY 可写)
-- PRIMARY 执行:
CREATE TABLE mysql._repl_test (id INT PRIMARY KEY);
INSERT INTO mysql._repl_test VALUES (1);
-- SECONDARY 执行:
SELECT * FROM mysql._repl_test;   -- 期望查到 id=1

六、注意事项汇总(易踩坑清单)

#事项影响
1SET GLOBAL gtid_purged 必须有(§4.2),且在 gtid_executed 为空、无复制通道时执行(RESET 后正好满足)缺 → 加入组重放历史撞数据,无法 ONLINE
2各节点内存需足够,innodb_buffer_pool_size 按各机实际内存核定不够 → 起不来/OOM
3CREATE USER IF NOT EXISTS,避免与已有 repl 账号重复重复 → ERROR 1396 中断
4PRIMARY 节点禁止 RESET MASTER / RESET SLAVE ALL执行 → 清空 binlog/GTID,全组无法追位点
5group_name 占位符须换成真实 UUID,各节点一致不一致 → 组无法互相识别
6member_expel_timeout=5 偏激进抖动误踢 → 可放宽 10~20
7binlog 保留时长(如 7 天)要足够从节点宕机超期 → donor binlog 已清,recovery 失败
8MGR 专用端口 + MySQL 端口放通不通 → 组通信/恢复失败
9kill_idle_transaction低风险:可能杀掉 recovery 空闲事务(留意)
10metadata 提取位点建议锚行首(如 grep '^Log:'/'^Pos:'误匹配 → 位点错误

七、补充:GreatSQL / GreatDB 差异

GreatSQL 是兼容 MySQL 8.0 的国产分支,MGR 参数、GTID 机制、开启/验证流程与 MySQL/MariaDB 完全一致,本篇主体可直接套用。差异集中在安装部署与服务名。以下为实测的具体步骤。

7.1 安装路径与数据目录

# GreatSQL 解压安装(路径/服务名按实际)
tar xf GreatSQL-8.0.32-XX-Linux-glibc2.28-x86_64.tar.xz -C /usr/local/
ln -s /usr/local/GreatSQL-8.0.32-XX-Linux-glibc2.28-x86_64 /usr/local/greatsql
mkdir -p /data/GreatSQL/ && chown -R mysql:mysql /data/GreatSQL/ && chmod -R 700 /data/GreatSQL/

# 初始化(空密码)+ 启动
/usr/local/greatsql/bin/mysqld --initialize-insecure --user=mysql
systemctl start greatsql
mysql -uroot -S /data/GreatSQL/mysql.sock -e "SELECT VERSION();"

7.2 服务名

systemctl restart greatsql   # GreatSQL 专用服务名,配置生效需重启

若用 GreatSQL 部署,主体中的 systemctl restart mysql 改为 systemctl restart greatsql

7.3 备份工具 mydumper / myloader

# 备份:从现有主库导出
nohup /usr/bin/mydumper -u root -p '密码' -h 源IP --less-locking \
  --threads=8 -s 10000000 --chunk-filesize=1024 \
  --outputdir=/data/dbbak/$(date +%Y%m%d) --compress=1 --ignore-sysdb=1 --verbose=3 \
  >> /tmp/backup.log 2>&1 &

# 恢复:到新节点
nohup /usr/bin/myloader -u root -p '' -S /data/GreatSQL/mysql.sock \
  --threads=8 --directory=/data/dbbak/$(date +%Y%m%d) \
  --verbose=3 --overwrite-tables >> /tmp/restore.log 2>&1 &

mydumper/myloader 是通用的 MySQL逻辑备份工具(非 GreatSQL 专有),但 GreatSQL 环境常用它做大数据量迁移;路径 /usr/bin/mydumper 为编译安装默认。

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝

目录