• MySQL高可用-MGR运维常见问题和注意事项

MySQL高可用-MGR运维常见问题和注意事项

2025-08-16 12:31:50 栏目:宝塔面板 35 阅读

MySQL 的高可用可以选择 MGR 方案,部署 MGR 很简单,可以参考《MySQL高可用-使用Docker部署MGR》,但在运行过程中,如果出现问题,如何快速解决?需要持续学习和实践。

下面我以实际用到的和我搜集到的一些资料来说说 MGR 在运维过程中的常见问题和注意事项。

部署前注意事项

硬件和环境要求

1、网络要求。

  • 低延迟网络:MGR 对网络延迟敏感,建议延迟 < 5ms 。因为 MGR 基于 Paxos 变种的共识算法,每提交一次事务至少跨网两次(prepare>ack>commit)。
  • 稳定带宽:确保有足够的带宽支持数据同步,建议 ≥ 1Gbps 。全量 recovery、大事务或 DDL 时会产生突发流量,带宽不足会导致 flow-control 触发,集群整体降速

2、服务器配置。

  • CPU:建议多核 CPU,至少4核以上
  • 内存:充足内存,建议 ≥ 16GB
  • 存储:使用 SSD 存储,确保足够 IOPS,考虑使用 RAID 10 而非 RAID 5/6,以获得更好的写性能
  • 时钟同步:所有节点必须时钟同步(NTP)。MGR 的 GTID、view_change 事件都带时间戳,时间漂移会导致 “member expel” 误判。误判会导致节点是正常的,但会被踢出去。
  • 分离数据和日志:将二进制日志和数据文件放在不同的物理存储上,参数大致如下:
datadir          = /data/mysql
log_bin          = /binlog/mysql-bin
binlog_cache_size           = 1M     
sync_binlog                 = 1
innodb_flush_log_at_trx_commit = 1

操作系统优化

1、文件描述符限制。

# 文件描述符限制
echo "mysql soft nofile 65536" >> /etc/security/limits.conf
echo "mysql hard nofile 65536" >> /etc/security/limits.conf

MGR + InnoDB 打开的文件数 = 表数量 × 分区 × 3(ibd、frm、ibtmp)+ binlog + relay log。文件描述限制如果比较小,操作系统层面的文件描述符(fd)耗尽,后果是 mysqld 再想去 open() 任何文件(包括新的 ibd、binlog、relay-log、tmp-file、socket 等)时都会得到 EMFILE,导致各种莫名奇妙的错误。

可以使用下面语句进行检查:

ulimit -n            # 当前会话
cat /proc/$(pidof mysqld)/limits | grep files

我在 CentOS 服务器上执行 ulimit -n 得到的结果是 1024 ,但在 MySQL 容器中的结果是 1048676 。

2、内核参数调优。

# 内核参数调优
echo "net.core.rmem_max = 134217728" >> /etc/sysctl.conf
echo "net.core.wmem_max = 134217728" >> /etc/sysctl.conf
sysctl -p

Linux 默认的 socket 缓冲区只有 128 KB,跨机房或云环境突发流量会触发 TCP 丢包重传,将该参数调大可降低重传率,提高吞吐。

可以通过 sysctl net.core.rmem_max net.core.wmem_max 进行检查。

3、内存优化。

# 内存优化
SET GLOBAL innodb_buffer_pool_size = 32*1024*1024*1024;

# 注释掉 /etc/fstab 里的 swap 行
sed -i '/swap/s/^/#/' /etc/fstab
  • 确保 innodb_buffer_pool_size 设置合理,通常为服务器内存的 50-75%
  • 确保系统不会使用交换空间,否则可能导致严重的性能下降。

监控

查看集成成员

SELECT
    MEMBER_ID       AS node_uuid,
    MEMBER_HOST     AS host,
    MEMBER_PORT     AS port,
    MEMBER_STATE    AS state,          -- ONLINE / RECOVERING / ERROR / OFFLINE
    MEMBER_ROLE     AS role            -- PRIMARY / SECONDARY
FROM performance_schema.replication_group_members
ORDER BY MEMBER_HOST;
  • state ≠ ONLINE:立刻报警。
  • role = PRIMARY:表示为主库。

复制延迟/事务堆积(只看当前节点)

SELECT
    MEMBER_ID                                 AS my_uuid,
    COUNT_TRANSACTIONS_IN_QUEUE               AS queue_txn,   -- >0 表示延迟
    COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE AS relay_txn,  -- 未应用完的 relay log 事务
    TRANSACTIONS_COMMITTED_ALL_MEMBERS        AS cluster_lsn, -- 全局已提交位点
    LAST_CONFLICT_FREE_TRANSACTION            AS last_no_conflict_txn
FROM performance_schema.replication_group_member_stats
WHERE MEMBER_ID = @@server_uuid;

根据经验进行判断:

  • queue_txn > 1000 或持续增长:延迟告警。
  • relay_txn > 1000 表示回放慢:需检查 applier 线程、IO 能力。

queue_txn 是其它节点已经提交、通过 Paxos 共识后广播给本节点,但本节点还没开始的事务数量。

正常情况下,事务来了立即被 applier 线程消耗,queue_txn 会瞬间降到 0。queue_txn 比较大说明有堵塞。

回放慢意思是当前节点的 applier 线程来不及重放远程事务,导致数据滞后。

applier 线程是什么呢 ?

在 MGR 里,可以把 applier 线程理解为真正把远程事务写进本地 InnoDB 的工人。检查 applier 线程、IO 能力其实就是确认:

  • 工人够不够。
  • 工人有没有被磁盘 IO 卡住。
  • 工人有没有报错/死锁。

先看有几个工人(applier 线程)。

SELECT THREAD_ID, NAME, PROCESSLIST_STATE
FROM performance_schema.threads
WHERE NAME LIKE '%group_rpl%applier%';

如果 PROCESSLIST_STATE 长期是 Waiting for disk space 或 Waiting for table flush,说明被 IO 堵住。

看工人是不是在慢吞吞地写。

SELECT 
    EVENT_NAME,
    SUM_TIMER_WAIT/1e9 AS total_seconds,
    MAX_TIMER_WAIT/1e9 AS max_seconds
FROM performance_schema.events_waits_summary_by_thread_by_event_name
JOIN performance_schema.threads USING(THREAD_ID)
WHERE NAME LIKE '%applier%'
  AND EVENT_NAME LIKE '%io%file%';

total_seconds 很大说明 applier 线程在磁盘 IO 上耗掉了大量时间。

看工人有没有报错。

SELECT
    WORKER_ID,
    LAST_ERROR_NUMBER,
    LAST_ERROR_MESSAGE,
    SERVICE_STATE          -- 显示线程是 ON / OFF
FROM performance_schema.replication_applier_status_by_worker
WHERE LAST_ERROR_NUMBER <> 0;

只要这条 SQL 返回了任何一行,就说明至少有一个 applier 线程曾经或正在报错,需要立即处理。

常见故障及排查

脑裂问题

正常情况下同一时间只能有一个节点是主节点,由于网络分区、参数配置等原因导致出现多个主节点,这就是脑裂。

症状识别

-- 检查是否存在多个PRIMARY
SELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE 
FROM performance_schema.replication_group_members 
WHERE MEMBER_ROLE = 'PRIMARY';

在一次网络分区后,节点可能会分成两派:

  • 多数派:仍然能够凑齐 >50 % 组内成员的那一边。例如 5 节点集群,有 3 台还是 ONLINE 状态,这一边就是多数派。只有多数派才能继续对外提供写服务,并且它们的投票结果才会被 MGR 认可。
  • 少数派:剩下的 ≤50 % 节点。这一侧因为凑不够“法定人数”,自动变为只读或离线,不再接受写请求。

解决方案

1、立即隔离写流量,把应用 VIP、proxy、DNS 指向全部下线,避免继续写。

2、快速定位合法主节点,找到拥有最新 GTID 集合且处于多数派的节点:

SELECT @@global.gtid_executed;
  • 在多数派中所有 ONLINE 节点上比较,选出 GTID 最大的那一个
  • 如果两边 GTID 相同,就保留原 PRIMARY;如果不同,以多数派里最新的为准。

3、多数派中的节点什么都不用做,不需要重启,不需要 bootstrap,保持 ONLINE 即可。

4、处理少数派节点,对节点进行下面操作:

STOP GROUP_REPLICATION;
RESET SLAVE ALL;          -- 清掉旧的通道
SET GLOBAL gtid_purged = '';  -- 如果确定这些节点落后很多
START GROUP_REPLICATION;  -- 让它重新加入并自动追赶
  • SET GLOBAL gtid_purged = '' 需要非常谨慎使用。这会清除节点的 GTID 执行历史,只有在确定节点数据已严重落后且准备重新同步全部数据时才应使用。在大多数情况下,不建议这样做,因为这可能导致数据丢失。更安全的做法是保留 GTID 历史,让节点基于现有数据追赶,或者如果数据差异太大,先备份后重建节点。

5、等所有节点回到 ONLINE 后,执行下面语句:

SELECT MEMBER_ID, MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members;

确保只有 1 个 PRIMARY,且所有节点 GTID 完全一致。

节点无法加入集群

常见原因

  • GTID 不一致
  • 网络连接问题
  • 版本不兼容
  • 配置错误

排查步骤

1、检查 GTID 状态。

SHOW GLOBAL VARIABLES LIKE 'gtid%';
SELECT @@GLOBAL.GTID_EXECUTED;

2、检查网络。

# 在故障节点上,对任一 ONLINE 节点测试
telnet ONLINE_IP 33061   # group_replication_local_address 的端口
-- 在问题节点上测试
SELECT * FROM performance_schema.replication_connection_status;
  • CHANNEL_NAME: group_replication_recovery(分布式恢复通道)和 group_replication_applier(正常应用通道)
  • SERVICE_STATE:ON = 连接正常;OFF = 连接断开;CONNECTING = 正在握手/重连。
  • LAST_ERROR_NUMBER / LAST_ERROR_MESSAGE:最近一次的 MySQL 错误号与文字描述。非 0 表示有问题。
  • RECEIVED_TRANSACTION_SET:当前节点已经从集群收到的 GTID 集合,可与 @@global.gtid_executed 对比判断落后多少。
  • COUNT_RECEIVED_HEARTBEATS:心跳计数,持续增加说明网络通;长时间不动可能丢包。
  • LAST_HEARTBEAT_TIMESTAMP:最后心跳时间,离当前时间越近越健康。

3、检查错误日志。

SHOW GLOBAL VARIABLES LIKE 'log_error';

解决方案

修复问题也需要分场景:

1、问题节点 GTID 落后,直接 START GROUP_REPLICATION; 即可自动追平,无需 RESET。

2、问题节点 GTID 超前,不执行 RESET MASTER ,而是把多出来的事务导出、在主库重放、再让节点重新加入。

3、问题节点 GTID 分叉,备份本节点、做差异校验、选择保留哪份数据。

4、GTID 为空,用克隆插件或全量备份 + CHANGE REPLICATION SOURCE 重建数据,再启动 MGR,不要手工 SET GTID_PURGED 。

怎么判断 GTID 是否落后还是超前?

1、在任意一个正常的 ONLINE 节点查看集群最新 GTID。

SELECT @@GLOBAL.GTID_EXECUTED;
-- 结果:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:1-5

2、在故障节点查看 GTID。

SELECT @@GLOBAL.GTID_EXECUTED;
-- 结果:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:1-3  表示落后
-- 结果:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:1-7  表示超前

本文地址:https://www.yitenyun.com/307.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 TIME_WAIT 运维 负载均衡 JumpServer SSL 堡垒机 跳板机 HTTPS JumpServer安装 堡垒机安装 Linux安装JumpServer Deepseek 宝塔面板 Linux宝塔 Docker 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 HexHub 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 服务器 管理口 HTTPS加密 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 Windows宝塔 Mysql重置密码 Oracle 处理机制 InnoDB 数据库锁 开源 PostgreSQL 存储引擎 无法访问宝塔面板 监控 连接控制 机制 Serverless 无服务器 语言 ES 协同 服务器性能 技术 Spring Redis 异步化 缓存方案 缓存架构 缓存穿透 分页查询 索引 高可用 group by Undo Log GreatSQL 连接数 SQL 动态查询 机器学习 日志文件 MIXED 3 响应模型 优化 万能公式 SVM Embedding R2DBC R edis 线程 数据 主库 自定义序列化 云原生 RocketMQ 长轮询 配置 工具 Netstat Linux 服务器 端口 Linux 安全 ​Redis 推荐模型 Postgres OTel Iceberg SQLark scp Linux的scp怎么用 scp上传 scp下载 scp命令 AI 助手 共享锁 PG DBA openHalo 向量数据库 大模型 SQLite-Web SQLite 数据库管理工具 存储 Hash 字段 Recursive 电商 系统 OB 单机版 查询 Ftp • 索引 • 数据库 架构 锁机制 流量 Rsync 修改DNS Centos7如何修改DNS 向量库 Milvus 人工智能 推荐系统 redo log 重做日志 数据分类 加密 磁盘架构 sftp 服务器 参数 线上 库存 预扣 场景 MySQL 9.3 聚簇 非聚簇 防火墙 黑客 业务 同城 双活 信息化 智能运维 Python 高效统计 今天这篇文章就跟大家 Doris SeaTunnel MVCC 传统数据库 向量化 不宕机 分库 分表 数据备份 mini-redis INCR指令 INSERT COMPACT 缓存 Redisson 锁芯 RDB AOF 网络架构 网络配置 窗口 函数 prometheus Alert PostGIS 启动故障 事务 Java 开发 Canal Web 崖山 新版本 filelock MongoDB 数据结构 IT运维 B+Tree ID 字段 分布式 集中式 ZODB 核心架构 订阅机制 引擎 性能 数据脱敏 加密算法 Go 数据库迁移 数据类型 虚拟服务器 虚拟机 内存 读写 容器 容器化 DBMS 管理系统 频繁 Codis 模型 JOIN Redis 8.0 网络故障 OAuth2 Token 国产数据库 聚簇索引 非聚簇索引 QPS 高并发 微软 SQL Server AI功能 Pottery 原子性 工具链 发件箱模式 自动重启 部署 Entity SpringAI 分页方案 排版 Testcloud 云端自动化 速度 服务器中毒 事务隔离 排行榜 排序 SSH Caffeine CP Web 接口 行业 趋势 数据页 数据集成工具 MCP 开放协议 悲观锁 乐观锁 StarRocks 数据仓库 Redka sqlmock LRU 大表 业务场景 dbt 数据转换工具 1 分页 优化器 AIOPS 分布式架构 分布式锁​ 池化技术 连接池 单点故障 仪表盘 网络 Order EasyExcel MySQL8 意向锁 记录锁 InfluxDB 事务同步 日志 RAG HelixDB IT 字典 播客 对象 双引擎 订单 单线程 主从复制 代理 Crash 代码 编程 Ansible UUIDv7 主键 UUID ID 恢复数据 LLM 语句 Valkey Valkey8.0 ReadView Pump 产业链 兼容性 数据字典 线程安全 Weaviate MGR 分布式集群 失效 List 类型 解锁 调优 Next-Key 表空间 分布式锁 Zookeeper 关系数据库 慢SQL优化 GitHub Git 查询规划 矢量存储 数据库类型 AI代理 RR 互联网 国产 用户 算法 千万级 快照读 当前读 视图 神经系统 count(*) count(主键) 行数 CAS 技巧 多线程 拦截器 动态代理 并发控制 恢复机制 闪回