Seconds_Behind_Master不能直接当端到端延迟用,因其仅为SQL thread执行事件时间戳与从库系统时间差值,扣除启动时计算的主从时钟差,且仅在IO和SQL线程均运行时有效。

Seconds_Behind_Master 为什么不能直接当延迟用
它不是“主库写完到从库查到”的端到端延迟,而是 SQL thread 当前执行事件的时间戳与从库系统时间的差值,中间还减去一个启动时计算的主从时钟差(clock_diff_with_master)。这个差值只在 SQL thread 正在跑、IO thread 也在线时才有意义。
常见错误现象:
-
Seconds_Behind_Master突然在 0 和 71 之间跳变 → 很可能是从库 NTP 校时后没重启复制线程,导致clock_diff_with_master还是旧值 - 值长期为 0,但业务刚写完就读不到 →
IO thread拉取慢(网络卡、主库 binlog 写太猛),SQL thread实际空闲,但还没东西可执行 - 值为
NULL→IO thread或SQL thread至少一个挂了,得先看Slave_IO_Running和Slave_SQL_Running
用 GTID 差集算积压事务数(MySQL 5.7+)
开启 GTID 后,Seconds_Behind_Master 更不可靠,真正反映延迟的是主库已生成但从库还没执行的事务数量。关键字段是 Retrieved_Gtid_Set(IO 已拉到 relay log 的事务)和 Executed_Gtid_Set(SQL 已执行完的事务)。
实操建议:
- 查待执行事务:运行
SELECT GTID_SUBTRACT(Retrieved_Gtid_Set, Executed_Gtid_Set) AS pending_sql FROM performance_schema.replication_applier_status_by_coordinator;,结果是 GTID 集合字符串,长度越长积压越多 - 避免在从库直接执行
SHOW SLAVE STATUS解析字符串——容易出错,优先走performance_schema表(MySQL 8.0.22+ 支持更细粒度字段) - 如果结果为空字符串,说明 SQL thread 已追平;如果返回类似
00000000-0000-0000-0000-000000000000:1-100,就说明有 100 个事务卡着没回放
建心跳表测真实业务延迟(推荐方案)
这是唯一能回答“用户刚下单,从库多久能查到”这个问题的方法。它绕开复制协议层,直击业务语义。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
实操建议:
- 建表语句必须是:
CREATE TABLE mysql_heartbeat (ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) ENGINE=InnoDB;,单行、无索引冗余、主键隐式存在(InnoDB 行级锁安全) - 主库更新用:
INSERT INTO mysql_heartbeat VALUES () ON DUPLICATE KEY UPDATE ts = NOW();(需提前插入一行) - 从库查询必须加
LIMIT 1:SELECT ts FROM mysql_heartbeat LIMIT 1;,否则全表扫描可能被锁阻塞,造成误报 - 禁止应用连接从库时用写权限账号操作该表——哪怕只是
UPDATE一次,也会污染心跳逻辑
监控脚本里别只盯一个值
单一指标会漏掉链路中某一段的真实瓶颈。主从复制本质是三段流水线:Binlog Dump → IO Thread → SQL Thread,每段都有独立信号。
一个健壮的检查脚本至少要同时采集:
-
Slave_IO_Running和Slave_SQL_Running:是否都为Yes -
Read_Master_Log_Pos与Exec_Master_Log_Pos差值:判断 IO 拉取是否积压(单位字节,需结合 binlog 文件大小看比例) -
Seconds_Behind_Master:仅作辅助参考,阈值告警慎设低于 60 秒 - 心跳表延迟:用
UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(ts)直接算秒数,这才是业务能感知的延迟
最容易被忽略的是:心跳表查询本身不能成为性能瓶颈——它必须轻量、确定、不争抢资源。一旦加了 WHERE、ORDER BY 或多行,就失去意义。

















