当前位置: 首页 > news >正文

Ubuntu 20.04 + MySQL 8.0 构建三节点MGR高可用集群实战

1. 项目概述:为什么在 Ubuntu 20.04 上配置 MySQL 组复制不是“选修课”,而是生产环境的必修动作

MySQL Group Replication(MGR)不是个新名词,但直到 Ubuntu 20.04 成为长期支持(LTS)主力发行版,配合 MySQL 8.0.13+ 的稳定成熟,它才真正从“实验室玩具”蜕变为可落地的高可用基石。我接手过三个线上系统——一个电商订单中心、一个金融风控日志平台、一个教育类 SaaS 的用户行为分析库,它们最初都用主从复制扛流量,结果无一例外在某次主库磁盘满、网络抖动或运维误操作后,出现数小时级的读写中断、数据不一致甚至脑裂。后来全部迁移到 MGR 架构,故障恢复时间从小时级压缩到秒级,且整个过程无需人工介入切换。这不是玄学,是基于 Paxos 协议的分布式共识机制在数据库层的真实兑现。Ubuntu 20.04 提供了干净、统一、长期受支持的运行时环境,内核 5.4、systemd 245、OpenSSL 1.1.1f 等组件版本与 MySQL 8.0 官方二进制包深度适配,避免了旧版 Ubuntu 中常见的 glibc 兼容性问题和 systemd 服务管理冲突。你可能看到热搜里全是“mysql安装教程”“ubuntu没声音20.04”,但真正决定系统生死的,从来不是那些表层功能,而是底层数据一致性保障能力。这个项目标题直指核心:它不是教你如何把 MySQL 装上系统,而是教你如何让三台(或更多) Ubuntu 20.04 服务器上的 MySQL 实例,像一个有机体一样协同工作、自动选举、故障自愈。适合谁?不是刚装完 MySQL 就想跑 SELECT * FROM users 的新手,而是已经经历过主从同步延迟报警、GTID 丢失、从库跳错位等痛楚的 DBA、SRE 或全栈工程师。如果你正为单点故障提心吊胆,或被业务方追问“数据库挂了多久能恢复”,那么接下来的内容,就是你该抄的第一份作业。

2. 整体设计与思路拆解:为什么放弃传统主从,坚定选择 MGR 的三重逻辑

2.1 架构选型不是技术炫技,而是对业务连续性的精准响应

很多人配置 MGR 是因为“听说它很新”,这非常危险。我见过团队花两周搭好三节点 MGR,结果上线后发现应用连接池没做读写分离,所有请求打到同一节点,其他两个节点纯属摆设;也见过因防火墙规则漏掉 group_replication_local_address 端口,集群永远无法形成。所以第一步必须回归本质:我们到底要解决什么问题?答案很朴素——消除单点故障,实现自动故障转移,保证数据强一致性。传统异步主从复制(Async Replication)有三个硬伤:一是主库宕机后,从库可能丢失最后几秒事务(异步特性决定);二是故障转移需人工干预或依赖外部工具(如 MHA),存在操作窗口期;三是多写场景下极易产生冲突(比如两个应用同时向不同从库写入同一条记录)。而半同步复制(Semi-sync)虽能缓解第一点,但无法解决后两点。MGR 则从根本上重构了逻辑:它不区分“主”和“从”,所有节点都是对等的(peer-to-peer),每个写入事务必须经过集群多数节点(quorum)确认才能提交,天然满足 CAP 理论中的 CP(一致性+分区容忍性)。这意味着,只要集群中存活节点数 ≥ ⌊N/2⌋+1(N 为总节点数),系统就始终可用且数据不丢。对于三节点集群,允许 1 台宕机;五节点则允许 2 台宕机。这种数学确定性,是任何脚本或中间件都无法提供的底层保障。

2.2 Ubuntu 20.04 与 MySQL 8.0 的组合,是当前最稳的生产基线

选择 Ubuntu 20.04 而非 18.04 或 22.04,并非偶然。18.04 的 MySQL 默认源只提供 5.7 版本,而 MGR 是 MySQL 5.7.17 才引入的实验性功能,到 8.0.13 才正式 GA(General Availability),稳定性、性能和文档完备度不可同日而语。22.04 虽然自带 MySQL 8.0.28+,但其 systemd 249+ 对 MySQL 服务单元文件(mysqld.service)的依赖解析更严格,曾导致我们一个客户在升级后 mysqld 启动失败,排查耗时半天。Ubuntu 20.04 的平衡点恰到好处:它通过官方 APT 源(http://archive.ubuntu.com/ubuntu focal-updates/main)稳定提供 MySQL 8.0.25(这是 2021 年发布的关键 LTS 版本),该版本修复了早期 8.0.x 中 group_replication_recovery_retry_count 参数失效、集群状态机卡死等致命 Bug。更重要的是,20.04 的内核 5.4 对 NUMA 架构支持更完善,在多路 CPU 服务器上能显著降低 MGR 心跳包(heartbeat)的延迟抖动,这对 Paxos 投票超时(group_replication_member_expel_timeout)的稳定性至关重要。我们实测过:在相同硬件上,Ubuntu 20.04 + MySQL 8.0.25 的集群平均投票延迟为 12ms,而 18.04 + 8.0.13 则高达 47ms,后者在高负载下极易触发误驱逐(expel)。

2.3 三节点最小集群的设计哲学:成本、复杂度与可靠性的黄金三角

MGR 官方文档建议至少三节点,但我们坚持“三节点是生产起步的绝对底线”,理由很实在。首先,两节点集群(2-node)在 MGR 中是伪高可用:当一台宕机,剩余一台无法构成多数派(quorum=2,需要 ≥2 节点同意),集群会整体只读甚至停止服务,这比单点更糟。其次,五节点虽容灾能力更强,但带来三重负担:一是网络开销翻倍(Paxos 消息广播量随节点数平方增长);二是运维复杂度指数上升(配置项、状态监控、故障排查维度成倍增加);三是硬件成本直接提升 60%。我们做过压测:在 10Gbps 网络下,三节点集群处理 5000 TPS 写入时,网络带宽占用率仅 12%;而五节点同等负载下,带宽占用率达 38%,且心跳包丢包率上升 3 倍。因此,三节点不是妥协,而是经过成本、性能、可靠性三维权衡后的最优解。它用最低的硬件投入,换取了生产环境必需的“单节点故障零感知”能力。后续扩展为五节点,应是业务规模翻倍、数据量激增后的自然演进,而非初始设计。

3. 核心细节解析与实操要点:绕不开的七个生死关卡

3.1 网络层:别让防火墙和 DNS 成为集群的“隐形杀手”

MGR 集群通信依赖两个独立端口:一个是 MySQL 服务端口(默认 3306),用于客户端连接和 SQL 流量;另一个是组复制专用端口(group_replication_local_address),用于节点间 Paxos 协议通信、心跳、状态同步。很多失败案例源于此。Ubuntu 20.04 默认启用 ufw(Uncomplicated Firewall),若未显式放行组复制端口,节点将永远无法握手。假设你规划节点 A(192.168.1.10)、B(192.168.1.11)、C(192.168.1.12),并为组复制分配 33061 端口,则必须在每台机器执行:

sudo ufw allow from 192.168.1.10 to any port 33061 sudo ufw allow from 192.168.1.11 to any port 33061 sudo ufw allow from 192.168.1.12 to any port 33061 sudo ufw reload

提示:切勿使用sudo ufw allow 33061开放所有来源,这会暴露集群内部协议,存在安全风险。必须精确到源 IP。

DNS 解析是另一大陷阱。MGR 要求所有节点能通过 hostname 相互解析(例如 node1.internal、node2.internal),但 Ubuntu 20.04 的 /etc/hosts 文件默认为空,且 systemd-resolved 服务可能干扰本地解析。我们的做法是彻底绕过 DNS,强制使用 IP。在 my.cnf 中,group_replication_local_address 必须写成192.168.1.10:33061,而非node1.internal:33061;同时,group_replication_group_seeds 必须列出所有节点的 IP:PORT,如"192.168.1.10:33061,192.168.1.11:33061,192.168.1.12:33061"。实测证明,IP 直连比 DNS 解析快 8-12ms,且杜绝了因 /etc/resolv.conf 配置错误导致的集群启动失败。

3.2 MySQL 配置:my.cnf 中那 12 行决定集群生死

MGR 对 MySQL 配置有严苛要求,少一行或多一行都可能导致集群无法启动或状态异常。以下是三节点集群中,每台机器 my.cnf [mysqld] 段落必须包含的 12 个核心参数(已按逻辑分组):

参数类别参数名推荐值关键原因
基础标识server_id1001 (A), 1002 (B), 1003 (C)必须全局唯一,且不能为 1(MySQL 8.0 默认值,易冲突)
GTID 强制gtid_modeONMGR 依赖 GTID 追踪事务,禁用则报错
enforce_gtid_consistencyON确保所有事务兼容 GTID,否则 CREATE TABLE ... SELECT 会失败
二进制日志binlog_formatROWMGR 仅支持行格式,STATEMENT 或 MIXED 会导致复制中断
log_bin/var/log/mysql/mysql-bin.log必须开启,MGR 从 binlog 读取事务事件
binlog_checksumNONEMySQL 8.0.20+ 默认 CRC32,但某些旧版客户端不兼容,设为 NONE 避免校验失败
组复制开关plugin_load_add'group_replication.so'动态加载插件,不加则插件无法启用
transaction_write_set_extractionXXHASH64生成事务写集(write set)的哈希算法,XXHASH64 性能最优
组通信group_replication_group_name"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"UUID 格式,三节点必须完全一致,建议用 uuidgen 生成
group_replication_local_address"192.168.1.10:33061"本节点监听地址,IP 和端口必须与防火墙规则匹配
group_replication_group_seeds"192.168.1.10:33061,192.168.1.11:33061,192.168.1.12:33061"种子节点列表,新节点加入时从此获取集群视图
group_replication_bootstrap_groupOFF仅在初始化第一个节点时临时设为 ON,其余节点必须为 OFF

注意:group_replication_bootstrap_group=ON是“雷区”。它只能在集群首次创建时,由第一个节点执行一次,且执行后必须立即设回 OFF。若第二个节点也设为 ON,会导致两个独立集群诞生,数据彻底分裂。我们封装了一个安全脚本:bootstrap-first-node.sh,它会自动检查 performance_schema.replication_group_members 表,确认无其他成员后再执行 START GROUP_REPLICATION。

3.3 用户与权限:那个被忽略的 replication_applier 账号

MGR 要求一个专用的复制用户(replication user),但很多人只创建了用于主从复制的用户,却忘了 MGR 的特殊需求。这个用户必须拥有BACKUP_ADMIN权限,这是 MySQL 8.0 新增的权限,用于在集群恢复(recovery)阶段读取其他节点的 binlog。缺失此权限,新节点加入时会卡在RECOVERING状态,日志报错Failed to start applier thread for channel 'group_replication_applier'。创建步骤如下(在第一个节点执行):

-- 创建用户(密码必须符合密码策略,建议用 mysql_native_password 插件) CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!'; -- 授予必要权限 GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; GRANT BACKUP_ADMIN ON *.* TO 'repl'@'%'; -- 刷新权限 FLUSH PRIVILEGES; -- 设置组复制恢复通道的凭据 SET GLOBAL group_replication_recovery_get_public_key = ON; CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='StrongPass123!' FOR CHANNEL 'group_replication_recovery';

实操心得:密码中必须包含大小写字母、数字和特殊字符,否则 MySQL 8.0 密码策略会拒绝。我们曾因密码太简单(如 'repl123')导致 recovery 通道认证失败,排查了 3 小时才发现是密码策略拦截。

3.4 启动顺序:为什么必须严格遵循“1-2-3”的物理时序

MGR 集群的启动不是并行的,而是有严格的物理依赖关系。错误的启动顺序是集群无法形成最常见的原因。正确流程如下:

  1. 启动节点 A(Bootstrap 节点):先确保 A 的 my.cnf 中group_replication_bootstrap_group=ON,然后启动 mysqld 服务。接着登录 MySQL,执行START GROUP_REPLICATION;。此时 A 进入ONLINE状态,但集群只有它自己。
  2. 启动节点 B:B 的 my.cnf 中group_replication_bootstrap_group=OFF,启动 mysqld 后,执行START GROUP_REPLICATION;。B 会向 seeds 列表中的 A 发起连接,A 将其接纳,B 状态变为RECOVERING(同步中),完成后变为ONLINE
  3. 启动节点 C:同 B,向 seeds 列表发起连接,最终三节点全部ONLINE

若跳过步骤 1,直接启动 B 和 C,它们会互相尝试连接,但因无引导节点,最终都卡在RECOVERING状态。若在 A 启动后未执行START GROUP_REPLICATION就启动 B,B 会因无法连接到有效集群而报错The group communication engine is not active。我们为此编写了start-mgr-cluster.sh脚本,内置 30 秒等待和状态轮询,确保前一节点ONLINE后再启动下一个。

3.5 状态监控:读懂 performance_schema 中的 5 张关键表

MGR 的健康状态不体现在SHOW PROCESSLIST,而深藏于 performance_schema 数据库。日常巡检必须掌握以下 5 张表:

  • replication_group_members:集群成员全景图。关注MEMBER_STATE(ONLINE/RECOVERING/OFFLINE/UNREACHABLE)和MEMBER_ROLE(PRIMARY/SECONDARY)。若某节点MEMBER_STATE=UNREACHABLE,说明网络或防火墙问题。
  • replication_group_member_stats:性能指标中枢。重点关注COUNT_TRANSACTIONS_IN_QUEUE(待处理事务数,持续 > 1000 表示同步延迟)、COUNT_TRANSACTIONS_CHECKED(已验证事务数)、COUNT_TRANSACTIONS_ROWS_VALIDATING(正在验证的行数)。
  • replication_connection_status:恢复通道状态。检查SERVICE_STATE是否为ONLAST_HEARTBEAT_TIMESTAMP是否在 5 秒内更新。
  • replication_applier_status_by_coordinator:协调器状态。THREAD_ID不为空且SERVICE_STATE=ON表示恢复线程正常。
  • replication_applier_status_by_worker:工作线程状态。LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP应与当前时间差 < 1 秒,否则存在延迟。

我们用一个简单的 Bash 脚本每分钟抓取这些值,当COUNT_TRANSACTIONS_IN_QUEUE > 5000MEMBER_STATE != 'ONLINE'时,自动发企业微信告警。这比依赖 Zabbix 的黑盒监控精准得多。

3.6 容灾演练:如何安全地模拟“杀掉一个节点”

纸上谈兵不如真刀真枪。我们每月进行一次容灾演练,步骤如下:

  1. 在节点 C 上执行sudo systemctl stop mysql,模拟宕机。
  2. 立即在节点 A 和 B 上执行SELECT * FROM performance_schema.replication_group_members;,确认 C 状态变为OFFLINE,A 和 B 仍为ONLINE
  3. 持续写入测试数据(如INSERT INTO test_table VALUES (UUID(), NOW());),观察COUNT_TRANSACTIONS_IN_QUEUE是否归零。
  4. 重启节点 C:sudo systemctl start mysql,然后执行START GROUP_REPLICATION;
  5. 观察 C 状态是否从RECOVERING变为ONLINE,且COUNT_TRANSACTIONS_IN_QUEUE先飙升后归零。

注意:演练中绝不能执行SET GLOBAL group_replication_bootstrap_group=ON在 C 上!这会创建新集群。C 必须以普通成员身份加入现有集群。

3.7 应用适配:你的代码可能正在悄悄破坏 MGR 的一致性

MGR 的强一致性是以牺牲部分灵活性为代价的。应用层必须遵守三条铁律:

  • 禁止跨库事务:MGR 要求事务的所有修改必须在同一数据库(schema)内。BEGIN; INSERT INTO db1.t1 ...; INSERT INTO db2.t2 ...; COMMIT;会直接报错ERROR 3092 (HY000): The table does not exist in the group replication members.。解决方案是拆分为两个独立事务,或使用数据库代理(如 ProxySQL)做路由。
  • 禁止非事务性引擎:MyISAM 表不支持事务,MGR 无法对其加锁和验证。所有表必须为 InnoDB。
  • 谨慎使用大事务:一个事务修改 100 万行,MGR 需为每一行生成 write set 并广播,极易导致网络拥塞和超时。我们规定单事务 DML 行数上限为 1 万,超限时由应用分批处理。

我们曾有个订单服务,因一个UPDATE orders SET status='shipped' WHERE create_time < '2023-01-01'语句影响 50 万行,导致集群心跳超时,节点被误驱逐。后来改为WHERE id BETWEEN ? AND ?分页执行,问题消失。

4. 实操过程与核心环节实现:从零开始搭建三节点集群的完整流水线

4.1 环境准备:三台 Ubuntu 20.04 虚拟机的标准化初始化

我们使用 VirtualBox + Vagrant 管理测试环境,但生产环境推荐 KVM 或云厂商的 ECS。三台机器配置完全一致:2 核 CPU、4GB 内存、50GB SSD 系统盘、100GB HDD 数据盘(挂载到/data/mysql)。初始化脚本init-ubuntu2004.sh包含以下关键步骤:

# 1. 更新系统并安装基础工具 sudo apt update && sudo apt upgrade -y sudo apt install -y vim curl wget net-tools iproute2 # 2. 创建 MySQL 数据目录并授权(避免默认 /var/lib/mysql 空间不足) sudo mkdir -p /data/mysql sudo chown -R mysql:mysql /data/mysql # 3. 配置时区和 locale(避免时间戳混乱) sudo timedatectl set-timezone Asia/Shanghai sudo locale-gen en_US.UTF-8 # 4. 关闭 swap(MySQL 对 swap 敏感,可能导致 OOM Killer 杀进程) sudo swapoff -a echo '# Disable swap' | sudo tee -a /etc/fstab sudo sed -i '/swap/d' /etc/fstab # 5. 调整内核参数(优化网络和内存) echo 'net.core.somaxconn = 65535' | sudo tee -a /etc/sysctl.conf echo 'vm.swappiness = 1' | sudo tee -a /etc/sysctl.conf sudo sysctl -p

实操心得:vm.swappiness=1是关键。Ubuntu 默认为 60,这意味着内核会积极将内存页换出到 swap,而 MySQL 的 buffer pool 若被 swap,性能会断崖式下跌。设为 1 后,仅在极端内存不足时才使用 swap,极大提升稳定性。

4.2 MySQL 8.0.25 的精准安装与服务配置

Ubuntu 20.04 官方源的 MySQL 8.0.25 是首选,避免手动下载二进制包带来的依赖风险。安装命令如下:

# 添加官方源(确保获取最新安全补丁) wget https://dev.mysql.com/get/mysql-apt-config_0.8.22-1_all.deb sudo dpkg -i mysql-apt-config_0.8.22-1_all.deb # 在交互界面中选择 MySQL Server & Cluster -> mysql-8.0 -> Apply sudo apt update sudo apt install -y mysql-server

安装完成后,不要运行sudo mysql_secure_installation,因为它会禁用 root 远程登录,而 MGR 节点间通信需要 root 权限。我们改用 SQL 命令精细化加固:

-- 登录 MySQL(默认 root 无密码) sudo mysql -- 创建专用管理用户(替代 root 远程访问) CREATE USER 'mgradmin'@'%' IDENTIFIED BY 'MgrAdminPass!2024'; GRANT ALL PRIVILEGES ON *.* TO 'mgradmin'@'%' WITH GRANT OPTION; -- 删除匿名用户 DELETE FROM mysql.user WHERE User=''; -- 刷新权限 FLUSH PRIVILEGES;

接着,编辑/etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]段落下添加前文所述的 12 个 MGR 参数。特别注意datadir必须指向/data/mysqlsocket改为/data/mysql/mysql.sock,以匹配我们创建的数据目录。

4.3 第一个节点(A)的引导与集群创建

节点 A(192.168.1.10)是集群的“心脏起搏器”。操作必须精确:

# 1. 编辑 my.cnf,设置 group_replication_bootstrap_group=ON sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf # 在 [mysqld] 下添加: # group_replication_bootstrap_group=ON # 2. 重启 MySQL 使配置生效 sudo systemctl restart mysql # 3. 登录并创建复制用户(如前所述) sudo mysql -u root -e " CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; GRANT BACKUP_ADMIN ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES; SET GLOBAL group_replication_recovery_get_public_key = ON; CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='StrongPass123!' FOR CHANNEL 'group_replication_recovery'; " # 4. 启动组复制(关键一步!) sudo mysql -u root -e "START GROUP_REPLICATION;" # 5. 验证状态 sudo mysql -u root -e "SELECT * FROM performance_schema.replication_group_members;" # 输出应显示:MEMBER_ID(A的UUID), MEMBER_HOST=192.168.1.10, MEMBER_PORT=3306, MEMBER_STATE=ONLINE, MEMBER_ROLE=PRIMARY

提示:START GROUP_REPLICATION执行后,需等待 10-15 秒再查状态。MGR 初始化 Paxos 状态机需要时间,立即查询可能返回空。

4.4 第二、三个节点(B 和 C)的加入与集群固化

节点 B(192.168.1.11)和 C(192.168.1.12)的配置与 A 几乎相同,唯独group_replication_bootstrap_group必须为 OFF。加入流程如下:

# 在节点 B 上执行(C 同理,仅 IP 地址不同) # 1. 确保 my.cnf 中 group_replication_bootstrap_group=OFF sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf # 2. 重启 MySQL sudo systemctl restart mysql # 3. 创建相同的复制用户(密码必须一致!) sudo mysql -u root -e " CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; GRANT BACKUP_ADMIN ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES; SET GLOBAL group_replication_recovery_get_public_key = ON; CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='StrongPass123!' FOR CHANNEL 'group_replication_recovery'; " # 4. 启动组复制(此时 seeds 指向 A 和 C,但 C 尚未启动,A 是唯一种子) sudo mysql -u root -e "START GROUP_REPLICATION;" # 5. 检查状态(B 应先为 RECOVERING,几分钟后变为 ONLINE) sudo mysql -u root -e "SELECT * FROM performance_schema.replication_group_members;"

当 B 和 C 都变为ONLINE后,集群即固化。此时可安全地将 A 的group_replication_bootstrap_group设回 OFF:

-- 在节点 A 上执行 sudo mysql -u root -e "SET GLOBAL group_replication_bootstrap_group=OFF;"

4.5 验证与压力测试:用真实数据检验集群韧性

集群ONLINE不代表万事大吉。必须进行两项验证:

1. 一致性验证:在 A 上创建测试表并插入数据,检查 B 和 C 是否实时同步。

-- 在节点 A 执行 CREATE DATABASE mgr_test; USE mgr_test; CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(50), ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP); INSERT INTO t1 VALUES (1, 'NodeA', NOW());

然后在 B 和 C 上执行SELECT * FROM mgr_test.t1;,结果必须完全一致。这是最基本的一致性保障。

2. 故障注入测试:这是最关键的一步。我们使用sysbench进行混合读写压力测试,同时模拟节点宕机:

# 在客户端机器安装 sysbench sudo apt install -y sysbench # 准备 100 万行测试数据 sysbench oltp_read_write --db-driver=mysql --mysql-host=192.168.1.10 --mysql-port=3306 --mysql-user=mgradmin --mysql-password=MgrAdminPass!2024 --tables=1 --table-size=1000000 prepare # 启动压测(16 线程,持续 300 秒) sysbench oltp_read_write --db-driver=mysql --mysql-host=192.168.1.10 --mysql-port=3306 --mysql-user=mgradmin --mysql-password=MgrAdminPass!2024 --threads=16 --time=300 --report-interval=10 run # 在压测进行到 60 秒时,执行:sudo systemctl stop mysql on Node C # 观察压测是否继续(应无缝切换到 A/B),错误率是否突增(理想情况 < 0.1%) # 120 秒后,重启 Node C,观察其是否自动加入并同步

实测结果:在 16 线程、300 秒压测中,当 C 节点宕机时,TPS 从 1250 微降至 1220(-2.4%),无事务失败;C 重启后 92 秒完成同步,COUNT_TRANSACTIONS_IN_QUEUE从峰值 8500 降至 0。这证明集群在真实负载下坚如磐石。

5. 常见问题与排查技巧实录:那些让我们熬夜到凌晨的坑

5.1 问题速查表:症状、原因与一键修复命令

症状可能原因诊断命令修复方案
SELECT * FROM performance_schema.replication_group_members;返回空MySQL 未启动,或 performance_schema 未启用sudo systemctl status mysqlsudo mysql -e "SHOW VARIABLES LIKE 'performance_schema';"确保performance_schema=ON(my.cnf 中),重启 mysqld
节点状态为UNREACHABLE防火墙阻止组复制端口,或group_replication_local_addressIP 错误telnet 192.168.1.10 33061(从 B 测试连通 A);sudo ss -tuln | grep 33061检查 ufw 规则,确认local_address使用本机实际 IP(非 127.0.0.1)
节点状态为RECOVERING且长时间不变化复制用户权限不足(缺BACKUP_ADMIN),或group_replication_recovery通道凭据错误sudo mysql -e "SELECT * FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='group_replication_recovery';"重新执行CHANGE MASTER TO ... FOR CHANNEL 'group_replication_recovery',确认用户有BACKUP_ADMIN
START GROUP_REPLICATION报错Plugin 'group_replication' is disabledplugin_load_add未正确配置,或group_replication.so文件不存在sudo mysql -e "SHOW PLUGINS;" | grep groupls /usr/lib/mysql/plugin/group_replication.so确认plugin_load_add='group_replication.so'在 my.cnf 中,且路径正确
集群形成后,新写入数据在其他节点查不到binlog_format不是ROW,或enforce_gtid_consistency=OFFsudo mysql -e "SELECT @@binlog_format, @@enforce_gtid_consistency;"修改 my.cnf,重启 mysqld
COUNT_TRANSACTIONS_IN_QUEUE持续 > 5000网络延迟高,或某节点 I/O 瓶颈(磁盘慢)ping 192.168.1.10iostat -x 1 5(在各节点执行)升级网络至 10Gbps;将 MySQL datadir 迁移至 SSD

5.2 “脑裂”(Split-Brain)的识别与紧急手术

脑裂是 MGR 最严重的故障:集群分裂为两个独立子集,各自接受写入,导致数据永久不一致。虽然 MGR 的多数派机制使其极难发生,但在极端网络分区(network partition)下仍有可能。识别方法:在节点 A 上执行SELECT * FROM performance_schema.replication_group_members;,发现只有 A 和 B;在节点 C 上执行,发现只有 C。此时,A 和 B 组成 quorum(2/3),C 被驱逐,但 C 仍认为自己在线。

紧急手术步骤(必须按顺序)

  1. 立即停止所有写入:通知应用团队,切断所有对集群的写请求。
  2. 确定“真理”集群:检查SELECT @@server_uuid;在 A 和 B 上,取server_uuid字典序较小者作为“主集群”(通常为最先启动的节点)。假设 A 的 UUID 更小。
  3. 重置“孤儿”节点 C:在 C 上执行STOP GROUP_REPLICATION; RESET MASTER; RESET SLAVE ALL;。这会清空 C 的所有复制元数据。
  4. 强制 C 以新成员身份加入:在 C 的 my.cnf 中,确保group_replication_bootstrap_group=OFF,然后START GROUP_REPLICATION;
  5. 验证数据一致性:使用pt-table-checksum工具对比 A 和 C 的关键表,若有差异,需从业务日志人工修复。

注意:绝不可在 C 上执行SET GLOBAL group_replication_bootstrap_group=ON!这会创建新集群,灾难无法挽回。

5.3 日志分析:读懂 error.log 中的“死亡预告”

MySQL error.log 是故障的晴雨表。以下日志片段预示着即将发生的严重问题:

  • [Warning] Plugin group_replication reported: 'Member with address xxx:3306 has become unreachable.'
    这是心跳超时的警告,若连续出现 3 次,该节点将被驱逐。立即检查网络和group_replication_member_expel_timeout(默认 5 秒,可调至 10 秒以适应高延迟网络)。

http://www.gsyq.cn/news/1580682.html

相关文章:

  • 银河麒麟V10安装Wireshark:权限配置与抓包实战指南
  • 2026年外贸独立站建站全攻略:从SEO到GEO,你的网站正在被AI“面试”
  • 嵌入式测试第 40 天:智能手表/手环嵌入式测试拆解
  • 1023. 【USACO题库】2.1.4 Healthy Holsteins健康的好斯坦奶牛
  • React对接DigitalOcean API:从零搭建前端数据流水线
  • 后端开发必看!6种服务端主动推送方案的实战对比
  • 深度解析:抖店行业资质与商品创建合规体系及实操准则
  • AI Agent核心原理与工程落地五模块详解
  • App Platform自定义域名、SSL与CDN配置原理与实战
  • Wireshark网络协议分析实战:从抓包入门到故障排查精要
  • Ubuntu 20.04 LEMP部署实战:Nginx+PHP7.4+MySQL8.0完整配置
  • 三步构建AI API使用数据自动化分析流水线:从账单到洞察
  • MC68010循环模式:硬件级指令优化与嵌入式性能提升
  • 2024年AIGC商业落地指南:从多模态大模型到实战应用
  • XSS攻击脚本全解析:从原理到实战绕过技巧与防御指南
  • MCU低功耗设计:SIM_SD寄存器精准控制外设时钟与唤醒机制
  • Postman自动化CSRF Token认证:环境变量与脚本实战指南
  • 跨越LLM产品评估可操作性差距:从数据到行动的系统方法
  • 零样本学习在软件工程情感分析中的创新应用
  • GLM-5.1代码能力跃迁:从SWE-Bench Pro登顶看大模型工程化落地
  • SRC漏洞挖掘入门指南:从零到一掌握白帽子实战技能
  • MC56F8455x SIM模块深度解析:复位、时钟与功耗管理实战指南
  • 飞书CLI实战指南:办公自动化从命令行开始
  • CentOS 8 安装 Node.js 三套可靠方案与避坑指南
  • 从脚本小子到安全猎人:40个核心姿势构建体系化漏洞挖掘思维
  • Python中__str__和__repr__方法的核心区别与工程实践
  • Gemini 3.1 Flash 计费逻辑深度解析:Token+推理强度双维定价
  • AI模型异常响应5分钟排查指南:从定位到修复的实战路径
  • Seedance 2.0:导演级视频生成与分镜脚本式提示词实践
  • Apache Traffic Server在Ubuntu 14.04上的反向代理实战