主库写了备库查不到?主从延迟四步定位法

十五年数据库相关经验,做过 DBA、架构师、技术顾问。不求"颠覆",只求"靠谱"。


主从同步这个事,看起来简单。主库写、备库读,binlog 传过去、relay log 回放完,齐活。

但真出问题时能要人命。

上个月接到一个告警,业务方反馈"刚下的订单查不到"。排查下来是主从延迟 30 秒——用户刚在主库写完,备库还没同步到。30 秒在互联网业务里就是"数据丢了"。

干了这么多年 DBA,主从延迟是最容易被低估、也最容易背锅的问题。今天把排查方法论整理出来,从"发现延迟"到"定位根因"到"解决",每一步都说清楚。

有好消息,也有踩坑的地方。各位耐心看完。


01 延迟从哪来?先搞清主从同步的完整链路

排查延迟之前,先搞清楚延迟可能出现在哪个环节。

主从同步不是"主库写完备库立刻就有",它是一整条链路:

第一步:主库写 binlog。主库执行写操作后,把变更记录写入 binlog 文件。这一步通常很快,毫秒级。

第二步:binlog 传输到备库。备库的 I/O 线程连接主库,拉取 binlog,写入备库的 relay log。这一步的延迟取决于网络带宽和 binlog 产生速度。

第三步:备库回放 relay log。备库的 SQL 线程(或者多线程复制的工作线程)读取 relay log,把变更重放到备库数据上。这一步是延迟的重灾区。

第四步:备库数据可见。回放完成后,新数据才能在备库上被查询到。

关键认知:主从延迟不是"一个数字",是整条链路累积的结果。排查时要逐段确认延迟出在哪个环节。


02 怎么发现延迟?别等业务方来报

主从延迟最可怕的不是"有延迟",是"有延迟但没人知道"。

等业务方反馈"刚写的数据查不到",问题已经发生很久了。DBA 应该在业务感知之前就发现并处理。

监控指标:看这三个数就够了

MySQL 8.0+:查询performance_schema.replication_connection_statusreplication_applier_status,关注LAST_HEARTBEAT_TIMESTAMP(最后一次心跳时间)和SERVICE_STATE(复制状态)。

MySQL 5.7:执行SHOW SLAVE STATUS,关注Seconds_Behind_Master(延迟秒数)和Slave_IO_Running/Slave_SQL_Running(复制线程状态)。

PostgreSQL:查询pg_stat_replication,关注write_lagflush_lagreplay_lag(分别对应写入、刷盘、回放延迟)。

三个阈值,分三级告警

延迟级别阈值响应动作
正常< 1 秒无需处理,常规监控
警告1-10 秒关注趋势,准备介入
危险> 10 秒立即排查,必要时切主

我的习惯:告警不要只设一个阈值。设三级,让团队知道"现在是什么状态"。只设一个"延迟 > 10 秒告警",等告警响了再查,黄花菜都凉了。


03 排查流程——四步定位法

发现延迟后,按这个流程走,90% 的主从延迟都能定位到根因。

第一步:确认延迟在主库还是备库

怎么看?

在主库执行一个写入操作,记录时间戳。然后在备库查询这条数据,记录看到的时间戳。两者之差就是端到端延迟。

如果延迟很大,但主库的 binlog 写入很快(查 binlog 文件大小增长速度),说明问题不在主库,在传输或回放环节。

第二步:确认是传输慢还是回放慢

怎么看?

MySQL 执行SHOW SLAVE STATUS,对比两个值:

  • Read_Master_Log_Pos:I/O 线程读到的主库 binlog 位置
  • Exec_Master_Log_Pos:SQL 线程回放到的位置

如果Read_Master_Log_Pos落后Master_Log_Pos(主库当前位置)很多,说明传输慢——网络带宽不够或者主库 binlog 产生太快。

如果Read_Master_Log_Pos跟得上,但Exec_Master_Log_Pos落后很多,说明回放慢——备库 SQL 线程处理不过来。

第三步:定位回放慢的具体原因

回放慢是最常见的延迟原因。具体又分几种情况:

情况 A:大事务回放。主库执行了一个大事务(比如批量更新了 100 万行),备库回放这个事务时,SQL 线程被占住,其他小事务都得排队等。

怎么看?SHOW PROCESSLIST,看备库 SQL 线程正在执行什么 SQL。如果是一条执行了几十秒还没完的 UPDATE 或 DELETE,基本就是大事务了。

情况 B:锁冲突。备库回放时遇到锁冲突,SQL 线程被阻塞。

怎么看?查备库的information_schema.innodb_trxdata_lock_waits,看有没有锁等待。

情况 C:备库硬件跟不上。主库用 SSD,备库用的是机械盘。同样的写入量,备库回放速度天然就慢。

怎么看?对比主备两端的磁盘 I/O 指标(iostat 看 iowait 和吞吐量)。如果备库磁盘利用率持续 100%,就是硬件瓶颈。

第四步:验证根因

定位到可能的根因后,验证一下:

  • 如果是大事务,在测试环境模拟同样规模的事务,看备库回放耗时。
  • 如果是锁冲突,分析锁等待链,确认阻塞源。
  • 如果是硬件瓶颈,做磁盘 I/O 压测,确认备库磁盘确实扛不住。

经验:不要猜根因,要验证。我见过太多 DBA 凭经验"觉得"是大事务导致的,结果查半天发现是备库磁盘满了。


04 解决思路——对症下药

定位到根因后,解决思路就清晰了。

方案 A:大事务 → 拆分事务 + 并行复制

大事务是主从延迟的头号杀手。一个事务更新了 100 万行,备库 SQL 线程要一条一条回放,可能花几十分钟。

治标:把大事务拆成小事务。原来一个 UPDATE 更新 100 万行,改成每次更新 1 万行,分 100 次执行。每次持锁时间短,备库回放也快。

治本:开启并行复制。MySQL 5.7+ 支持多线程复制(MTS),备库可以用多个线程并行回放不同库或不同事务的变更。

-- MySQL 开启并行复制(基于库的并行)SETGLOBALslave_parallel_workers=4;-- MySQL 5.7+ 基于逻辑时钟的并行复制(推荐)SETGLOBALslave_parallel_type='LOGICAL_CLOCK';SETGLOBALslave_parallel_workers=8;

注意:并行复制不是线程越多越好。线程数超过 CPU 核心数后,收益递减。一般设成 CPU 核心数的 1-2 倍。

方案 B:网络传输慢 → 压缩 + 带宽扩容

如果确认是 binlog 传输慢,两个方向解决:

开启 binlog 压缩:MySQL 5.7+ 支持 binlog 传输压缩,在网络带宽紧张时能显著降低传输量。

-- 主库开启 binlog 压缩SETGLOBALbinlog_transaction_dependency_tracking='WRITESET';

扩容网络带宽:如果主备跨机房部署,网络带宽是硬瓶颈。该升级就升级,别省这个钱。

方案 C:备库硬件瓶颈 → 升级存储 + 读写分离

如果备库硬件确实扛不住,两条路:

短期:把备库的读流量切一部分走主库,降低备库负载。

长期:升级备库存储。把机械盘换成 SSD,或者上 NVMe。硬件升级的钱,比延迟导致业务损失的钱少多了。


对比:三种复制方案的延迟表现

把上面的内容做个对比,方便选型:

方案延迟范围适用场景局限性
单线程复制秒级到分钟级小数据量、低写入频率大事务必延迟
基于库的并行复制亚秒级到秒级多库部署、写入分散单库大事务仍然慢
基于逻辑时钟的并行复制亚秒级生产环境推荐需要 MySQL 5.7+
半同步复制毫秒级(但有写入延迟)数据零丢失场景主库写入变慢

选型建议:生产环境优先用基于逻辑时钟的并行复制(MTS)。数据安全性要求极高的场景,用半同步复制,但接受主库写入性能的轻微下降。


延迟容忍度的判断框架

不是所有场景都需要"零延迟"。按业务容忍度分三档:

容忍度高(延迟 < 10 秒可接受)

  • 后台报表查询
  • 数据分析任务
  • 非实时用户查询
  • 方案:标准异步复制 + 常规监控

容忍度中(延迟 < 3 秒可接受)

  • 用户个人中心查询
  • 商品详情查询
  • 订单状态查询
  • 方案:并行复制 + 三级告警 + 自动切换

容忍度低(延迟 < 1 秒可接受)

  • 账户余额查询
  • 实时库存查询
  • 支付状态确认
  • 方案:半同步复制 + 强制走主库查询 + 秒级监控

我的经验:不要一刀切要求"主从零延迟"。不同业务场景对延迟的容忍度不同。按场景分级治理,比统一高标准更务实。


从"主从延迟是玄学"到"延迟是可管理的"

说实话,干 DBA 前五年,我对主从延迟的态度是"能忍就忍"。延迟几秒嘛,业务又不会挂。

后来接了几个金融项目才明白:延迟不是"能不能忍"的问题,是"业务允不允许"的问题。证券交易系统,延迟 1 秒就是"数据不一致",合规上过不了关。

这个认知转变让我重新审视主从延迟的排查方法。以前是"延迟大了再看",现在是"持续监控、分级治理、提前预警"。

主从延迟不是玄学,是可测量、可定位、可优化的工程问题。


深度分析:为什么并行复制不能解决所有延迟问题?

很多人以为"开了并行复制就万事大吉"。实际不是这样。

并行复制解决的是"多个小事务排队等"的问题。但如果来了一个大事务(比如批量删除 1000 万条过期日志),再多的并行线程也得等这个事务回放完。

根因在于:大事务本身是一个不可分割的原子操作。备库不能把一个事务拆成两半来回放——那会破坏事务的原子性。

所以并行复制有天花板。它能解决并发小事务的延迟,解决不了单一大事务的延迟。

真正的解法是:从源头控制事务大小。应用层做批量操作时,分批提交。每批 1000-5000 行,不要一个事务搞定。

这个道理和 DBA 的日常建议一致:事务尽量短。不仅是为了减少锁等待,也是为了减少主从延迟。


主从延迟巡检清单

日常巡检建议每周执行一次:

1. 延迟趋势检查

  • 查看过去一周的延迟曲线,确认没有持续增长趋势
  • 如果延迟峰值在上升,说明复制能力在下降,需要排查

2. 复制线程状态

  • 确认 I/O 线程和 SQL 线程都在运行
  • 如果有线程停过,查错误日志看原因

3. 大事务监控

  • 查看主库 binlog 中事务大小的分布
  • 如果出现异常大的事务,通知应用团队优化

4. 硬件资源检查

  • 备库磁盘 I/O 利用率是否接近上限
  • 备库 CPU 和内存使用是否正常

5. 告警规则验证

  • 确认三级告警阈值配置正确
  • 测试告警通道是否正常(发一条测试告警确认能收到)

总结

主从延迟排查就一套流程:看监控 → 分段定位 → 验证根因 → 对症下药。

核心认知:延迟不是"一个数字",是整条链路累积的结果。传输慢和回放慢是两回事,不能混为一谈。

预防延迟的关键:事务要短、复制要并行、监控要分级。

处理过几十次主从延迟问题,每次回到这套流程,问题都能解决。不需要什么高级工具,耐心和方法论就够了。

后续我会继续分享数据库参数调优实战、容量规划方法论这些话题,跟着我一篇篇学,数据库这块就没问题了。

有问题评论区见。


十五年数据库领域老炮。关注我,一起把数据库这件事搞明白。