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

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

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

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