MySQL 主从复制延迟排查与优化实战

MySQL 主从复制延迟是读写分离架构下最让 DBA 头疼的问题之一:从库明明在跑,数据却总是比主库”慢半拍”。当延迟从几百毫秒攀升到几十秒,下游的报表、缓存预热、搜索索引都会读到过期数据,轻则业务对账出错,重则引发超卖与资损。本文从延迟的成因讲起,给出可落地的观测手段、根因排查清单,以及并行回放、大事务拆分、读写分离策略等优化方案,并结合一次真实排障案例带你完整走通根治流程。

一、什么是主从复制延迟

MySQL 的主从复制(replication)通过主库把变更写入 binlog,从库的 I/O 线程拉取 binlog 到本地 relay log,再由 SQL 线程(或 Worker 线程)回放,从而在从库重建一份相同的数据。所谓”复制延迟”,就是指从库回放进度落后于主库写入进度的时间差。在 8.0 之后,官方用 Seconds_Behind_Source 这个指标来近似表达这个差值(旧版本叫 Seconds_Behind_Master)。需要强调的是,它只是一个近似值:它反映的是从库 SQL 线程当前正在回放的事务,在主库上被执行的时间点之差,并不等同于业务视角的数据一致性延迟。

二、延迟是怎么产生的

复制链路是一条流水线,任何一段变慢都会成为瓶颈。理解下列环节,是后续排查的基础。

2.1 单线程回放的瓶颈

早期 MySQL 只有单个 SQL 线程顺序回放 relay log,而主库是可以多线程并发写入的。主库 1 秒能提交 1 万笔事务,从库却只能 1 秒回放 2000 笔,差距自然越积越大。这是最常见的延迟根因,也是 5.7 之后引入多线程复制(MTS)要解决的痛点。

2.2 大事务与 DDL

一个一次性删除 500 万行的 DELETE、一次锁表数分钟的 ALTER TABLE,都会在主库瞬间完成(或快速执行),但到了从库要逐行回放或被 MDL 锁阻塞,回放时间被拉长成”尖峰延迟”。此外,从库上如果有长事务、慢查询占着锁,SQL 线程也会被卡住。

三、如何观测延迟

观测不能只看一个数字。最常用的是在从库执行 SHOW REPLICA STATUS\G(8.0 之前是 SHOW SLAVE STATUS\G):

mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_Running: Yes
            Replica_SQL_Running: Yes
          Seconds_Behind_Source: 28        -- 关注这个值
      Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Retrieved_Gtid_Set: 3e11fa47-71ca-11e1-9e33-5254afb5af23:1-10086
            Executed_Gtid_Set: 3e11fa47-71ca-11e1-9e33-5254afb5af23:1-10058  -- 比上面少 28 个事务

当 Seconds_Behind_Source 偏大但看不出原因时,对比主从的 GTID 集合差值、或对比 Relay_Master_Log_File / Exec_Master_Log_Pos 与主库当前位点,能精确定位”卡在哪一个 binlog 事件”。把这两个位点差接入 GitHub Actions 驱动的监控任务,就能做到延迟越线自动告警。

四、常见根因与排查清单

遇到延迟,先按下面的对照表逐项排除,往往能三分钟定位:

根因典型现象快速排查命令
从库硬件/配置弱于主库持续中等延迟,无尖峰对比 innodb_buffer_pool_size、CPU 核数
单线程回放瓶颈主库高并发时延迟线性增长看 Replica_SQL_Running_State 是否常驻回放
大事务 / 大 DDL突发尖峰,几秒到几十分钟查主库 binlog 中大事务、information_schema
从库慢查询占锁延迟周期性卡住SHOW PROCESSLIST 看长事务与 MDL 锁
网络带宽 / 跨机房IO 线程延迟、relay 落后测主从之间 iperf、ping 时延

五、优化方案

5.1 开启并行回放(多线程复制)

这是性价比最高的优化。MySQL 5.7+ 支持基于逻辑时钟(LOGICAL_CLOCK)的并行回放,8.0 进一步支持基于 WRITESET 的依赖跟踪,能更激进地并行化。在从库配置:

# my.cnf (从库)
[mysqld]
server-id = 2
relay_log = relay-bin
# 并行回放:基于 WRITESET 冲突检测,并行度最高
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 8          # 一般设为 CPU 核数的 1/2~1
slave_preserve_commit_order = ON    # 保证提交顺序,避免数据不一致
# 8.0 推荐同时开启 writeset 依赖追踪
binlog_transaction_dependency_tracking = WRITESET
transaction_write_set_extraction = XXHASH64

改完重启从库复制线程即可。多数”持续中等延迟”场景,仅此一项就能把延迟从十几秒压到 1 秒以内。注意:并行度不是越大越好,worker 间协调也有开销,建议结合压测调参。

5.2 拆分大事务

对一次性大批量删除/更新,拆成小批次、带 LIMIT 的循环,能让主从”齐步走”,避免从库一次性回放巨事务被卡成尖峰:

-- 不要这样:从库要回放一整条巨事务
DELETE FROM order_log WHERE created_at < '2024-01-01';

-- 改成小批循环(应用层或存储过程),每次只删 5000 行
DELETE FROM order_log WHERE created_at < '2024-01-01' LIMIT 5000;
-- 循环执行,直到影响行数为 0

线上 DDL 优先用 Docker 里跑的 gh-ost 或 pt-online-schema-change 做无锁变更,避免 MDL 锁把复制线程长时间阻塞。

5.3 网络与硬件基线

跨机房、跨云的主从,先把网络时延和带宽打到基线:主从之间建议同可用区或专线;从库 innodb_buffer_pool_size 至少不低于主库,磁盘用 SSD。若主库写入量确实远超单从库回放能力,考虑增加从库数量做负载分摊,或用 Redis 缓存承接读热点,减轻从库压力。

5.4 读写分离的延迟容忍策略

架构层面要做”延迟感知”:对强一致性要求高的请求(如支付后查余额)走主库;对容忍秒级过期的请求(如报表、评论列表)才走从库。也可在主库写入后,把关键主键短暂标记为”需读主”,规避刚写入即从库读不到的窗口。

六、实战案例:一次 30 秒延迟的根治

某业务从库持续 30 秒延迟告警。第一步 SHOW REPLICA STATUS\G 看到 Seconds_Behind_Source: 30 且在涨;第二步看 Replica_SQL_Running_State 卡在回放某张大表的 DELETE;第三步上主库翻 binlog,发现凌晨有个一次性清理 6000 万行 order_log 的定时任务,单事务巨无霸。根因明确:单事务回放 + 单线程瓶颈叠加。

修复动作:① 临时把清理任务改为 LIMIT 5000 分批;② 给从库加上 slave_parallel_workers=8 + WRITESET;③ 把这类大批量任务统一收敛到业务低峰,并接入延迟监控。三天后延迟稳定收敛到 1 秒以内。事后复盘也顺带优化了 PG 慢查询 与 PostgreSQL 侧的类似任务,避免同类问题。

七、总结

排查 MySQL 主从复制延迟 的口诀是:先观测(SHOW REPLICA STATUS + 位点/GTID 对比),再对照根因清单定位,最后用”并行回放 + 大事务拆分 + 读写分离延迟容忍”三板斧根治。把延迟指标接入监控告警,才能把问题消灭在业务感知之前。复制链路虽长,但只要按本文的流水线思路逐段击破,绝大多数延迟都能稳定压到秒级以内。

上一篇 集群脑裂排查实战:Redis 与 MySQL 双主写冲突根治
下一篇 僵尸进程排查实战:Linux 下僵尸进程的成因与清理
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]