seconds_behind_master不准是因为它仅反映sql线程与i/o线程的时间差,不包含已写入relay log但未执行的binlog事件;大事务、网络抖动、relay_log切换等均会导致其跳变或归零,无法真实反映业务读写延迟。

查 Seconds_Behind_Master 为什么不准?
它只是从库 SQL 线程和 I/O 线程之间的时间差,不是真实业务读写延迟。主库写入快、从库大事务卡住、网络抖动、甚至 relay_log 切换瞬间都会让这个值跳变或归零,但实际数据还没应用完。
- 真正有风险的是「已写入 relay log 但未执行的 binlog event」——
Seconds_Behind_Master不反映这部分积压 - 如果从库正在执行一个耗时 30 秒的大
UPDATE,Seconds_Behind_Master可能显示 0,但新读请求会命中旧数据 - 建议配合
SHOW SLAVE STATUS\G中的Exec_Master_Log_Pos和Read_Master_Log_Pos差值判断 relay log 积压量
用 pt-heartbeat 做秒级延迟探测
它在主库定时更新一张心跳表,从库读取该行时间戳并和本地时间比对,结果更贴近真实复制延迟,且不受大事务阻塞影响。
- 必须在主库创建专用心跳表:
CREATE TABLE heartbeat.heartbeat (ts TIMESTAMP NOT NULL PRIMARY KEY) - 启动探测命令要带
--update(主库)和--monitor(从库),不能只跑一次:pt-heartbeat --DSN h=master_host,u=replicator --update --daemonize - 监控脚本里别直接用返回值做告警阈值,
pt-heartbeat默认输出单位是秒,但可能含小数(如0.23),需用awk '{print $2}'提取字段再判断
读请求路由前检查 slave_sql_running 和 slave_io_running
这两个状态为 No 时,Seconds_Behind_Master 就完全失效,但很多中间件或应用层仍会把流量打过去。
- 检查语句必须用
SHOW SLAVE STATUS\G,不能依赖SHOW VARIABLES或SHOW PROCESSLIST - 只要任一值为
No,应立刻将该从库从读池摘除,而不是等延迟超阈值再处理 - 注意 MySQL 8.0.22+ 引入了
replica_sql_running和replica_io_running,变量名变了,旧版客户端若没适配会导致误判
应用层加 SELECT /*+ MAX_EXECUTION_TIME(1000) */ ... 防雪崩
当主从延迟突增,大量读请求堆积在从库上,可能拖垮 SQL 线程,形成恶性循环。强制超时能避免单个慢查询卡死整个复制链路。
- 这个 hint 只在 MySQL 5.7+ 支持,且需开启
max_execution_time功能(默认关闭) - 不建议全局设置
max_execution_time,容易误杀正常长查询;应在关键读接口的 SQL 上显式加 hint - 超时后应用需捕获
Query execution was interrupted错误(错误码 1317),而非当作数据不存在处理
INSERT,也可能是 2 秒前开始执行的一个锁表 ALTER。监控得盯住源头,而不是只看仪表盘上的那个数字。










