发布时间:2026-09-16 04:31 更新时间:2026-09-16 04:31 阅读量:0
很多站长第一次看到监控里的主从延迟曲线,都会有点懵:Seconds_Behind_Master 一会儿跳到 300,一会儿又回到 0,既不像彻底断掉,也不像稳定滞后。这个指标本身只是个估算值,它比较的是从库 SQL 线程当前执行到的事件时间戳与从库系统时间之差,所以只要主库上有一个长事务提交,或者从库上有个查询压着锁不放,它就会瞬间被拉高再回落。
要把它查清楚,思路是从主库写入端、从库执行端、复制线程状态三条线同时看,而不是盯着这一个数字反复刷新。下面按排查顺序展开。
第一步永远是登录从库看复制线程的真实状态,而不是只看监控面板。执行下面的语句,重点关注 Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master 以及 Relay_Log_Pos 是否在持续推进。
mysql -uroot -p -e "SHOW SLAVE STATUS\G" | egrep -i \
"Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Relay_Log_Pos|Relay_Master_Log_File|Read_Master_Log_Pos"
如果 IO 线程是 Yes、SQL 线程也是 Yes,Seconds_Behind_Master 却反复跳变,那基本可以判定主从链路是通的,问题出在某个时间段内从库执行跟不上。这时可以连续采几次位置信息,看 Relay_Log_Pos 是否在涨:不涨说明 SQL 线程卡住,涨但慢说明执行效率不够。
还有一种常见情况是 SQL 线程空闲时该字段显示为 NULL,而不是 0,这在部分版本里属于正常表现,具体以官方文档和实际环境为准,不必当成故障处理。
延迟忽高忽低,十有八九来自主库上的批量操作。一个几百万行的 UPDATE、一次全表 ALTER、一批 LOAD DATA,都会在 binlog 里形成单个大事务,从库必须整段执行完才提交,期间延迟数字就会一路走高,执行完立刻回落。
先看主库当前有没有长事务在跑:
SELECT trx_id, trx_state, trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS run_seconds,
trx_rows_modified
FROM information_schema.INNODB_TRX
ORDER BY run_seconds DESC LIMIT 10;
run_seconds 动辄几百秒、trx_rows_modified 很大的记录,就是要重点关注的对象。再配合 SHOW PROCESSLIST 看是哪条业务 SQL 发起的,能对上业务逻辑就更好定位。
如果确认是批量写造成,可以从两头缓解:一是把大事务拆成小批次提交,比如每 1000 行 COMMIT 一次;二是调整从库的并行复制,让不同 schema 或不同事务组能并发回放。MySQL 5.7 之后可用基于逻辑时钟的并行复制,参数大致如下,具体取值以官方文档为准:
# 从库 my.cnf 中设置
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 8
slave_preserve_commit_order = 1
注意 slave_preserve_commit_order 在开启并行复制时需要打开,否则可能出现从库数据短暂不一致。修改后需要重启或动态设置并重启复制线程。
如果主库写入很平稳,从库却经常卡顿,那多半是读业务和复制线程在抢锁。从库上跑的报表查询、全表统计如果持有长时间的行锁或元数据锁,SQL 线程就只能排队等。
查看当前的锁等待情况:
SELECT r.trx_id AS waiting_trx, r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query, b.trx_id AS blocking_trx,
b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_query
FROM information_schema.INNODB_LOCK_WAITS w
JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id
JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;
如果 blocking_query 是慢查询或报表 SQL,而 waiting_query 来自复制线程,那就说明读业务拖累了回放。处理办法包括:把重查询挪到只读从库、给报表加索引、限制单次查询扫描行数,必要时用 max_execution_time 给查询加超时保护。
另外别忘了检查从库的慢查询日志,把 long_query_time 调小一点,先抓出耗时最长的几条,再决定优化方向。
Seconds_Behind_Master 忽高忽低,本质上是「主库写入节奏」和「从库回放能力」之间的瞬时差值。排查顺序建议固定下来:先确认复制线程状态与位点是否推进,再看主库有没有大事务和批量写入,最后查从库的锁等待与慢查询。三处都确认后,再决定是拆事务、开并行复制,还是把重查询迁走。
如果延迟长期存在而不是偶发,还要顺带关注从库的磁盘 IO 和 CPU 使用率,硬件瓶颈同样会让回放变慢。建议把复制状态纳入日常监控,采集位点差值而不只是看那一个估算字段,这样出现波动时才有历史数据可对照。
| 📑 | 📅 |
|---|---|
| 容器内存超限被 OOM Kill 排查:指标、cgroup 与堆参数对应 | 2026-09-16 |
| Nginx 499 状态码排查实战:客户端断连与 upstream 超时的区别 | 2026-09-16 |
| 服务器定时任务实战:crontab 语法与不生效排查 | 2026-09-15 |
| MySQL慢查询日志开启与优化入门 | 2026-09-15 |
| Docker Compose 部署多容器应用实战:环境变量、数据卷与重启策略配置要点 | 2026-09-15 |
| rsync 增量同步与断点续传实战:exclude、--delete 与限速 | 2026-09-16 |
| Nginx 后端真实 IP 获取:X-Forwarded-For 与 real_ip 配置 | 2026-09-16 |
| Linux文件句柄耗尽排查:Too many open files 从ulimit到systemd | 2026-09-16 |
| PostgreSQL 连接数与内存调优:max_connections 与 shared_buffers 怎么配 | 2026-09-16 |
| 服务器时间不同步导致证书与定时任务异常:NTP/chrony 校时配置与排查 | 2026-09-16 |