seconds_behind_master不能单独用作告警依据,因其是mysql估算的逻辑延迟,在io线程中断、sql线程卡死、并行复制启用时易失真(显示null或0),需结合slave_io_running、slave_sql_running及relay_log_pos等状态综合判断,并推荐使用pt-heartbeat获取真实端到端延迟。

Seconds_Behind_Master 不能单独用作告警依据,它在 IO 线程中断、SQL 线程卡死、并行复制启用时经常失真(显示 NULL 或 0),直接设阈值会漏报或误报。
为什么不能只看 Seconds_Behind_Master
这个字段是 MySQL 自己估算的“逻辑延迟”,不是真实端到端耗时。常见失效场景包括:
-
Slave_IO_Running为No时,Seconds_Behind_Master可能仍显示0或旧值 - 启用了
slave_parallel_type = LOGICAL_CLOCK且事务提交顺序复杂时,计算结果偏差大 - SQL 线程正执行一个大事务(比如
ALTER TABLE),但Seconds_Behind_Master暂时没更新 - 从库重启后 relay log 尚未重建完成,该字段为
NULL
真正可用的阈值判断逻辑
必须组合至少三个状态字段,缺一不可:
-
Slave_IO_Running和Slave_SQL_Running都必须为Yes -
Seconds_Behind_Master是数字且大于阈值(例如60) - 若
Seconds_Behind_Master为NULL,需进一步检查:Relay_Log_Pos和Read_Master_Log_Pos是否长期未变化(比如 30 秒内差值不变)
Shell 脚本中建议这样写判断:
DELAY=$(mysql -u$USER -p$PASS -e "SHOW SLAVE STATUS\G" | grep "Seconds_Behind_Master" | awk '{print $2}')
IO_STATUS=$(mysql -u$USER -p$PASS -e "SHOW SLAVE STATUS\G" | grep "Slave_IO_Running" | awk '{print $2}')
SQL_STATUS=$(mysql -u$USER -p$PASS -e "SHOW SLAVE STATUS\G" | grep "Slave_SQL_Running" | awk '{print $2}')
<p>if [[ "$IO_STATUS" != "Yes" || "$SQL_STATUS" != "Yes" ]]; then
echo "CRITICAL: replication thread down"
elif [[ "$DELAY" =~ ^[0-9]+$ ]] && [ "$DELAY" -gt 60 ]; then
echo "ALERT: delay $DELAY seconds"
elif [[ "$DELAY" == "NULL" ]]; then</p><h1>追加 relay log 位置停滞检测</h1><p>...
fi</p>
用 pt-heartbeat 替代单点阈值
pt-heartbeat 不依赖 MySQL 内部状态,而是主库定时写心跳记录、从库读取并计算真实延迟,适合跨机房、GTID、大事务等复杂场景。
- 主库运行:
pt-heartbeat --daemonize --update --user=root --password=xxx --host=master-host - 从库查延迟:
pt-heartbeat --check --user=root --password=xxx --host=slave-host - 输出值如
1.23表示真实延迟 1.23 秒,比Seconds_Behind_Master可靠得多 - 配合 Prometheus 抓取时,建议用
pt-heartbeat --monitor输出格式化指标
阈值设定要考虑业务容忍度,不是越小越好
设成 5 秒可能每天告警十几次——网络抖动、单条慢查询、临时锁表都会触发。实际应按业务分级:
- 核心交易库:可设
30秒,但必须搭配pt-heartbeat验证 - 报表/分析从库:
300秒更合理,避免干扰运维节奏 - 人为延迟复制(
MASTER_DELAY = 3600):告警阈值应设为3600 ± 60,防止偏离预期
最易被忽略的是:告警脚本里没处理 NULL 值和线程状态,导致故障发生时静默;以及把 pt-heartbeat 心跳表建在非 system 库,被备份策略误删。











