seconds_behind_master不能直接告警,因其常为null或0却实际存在严重延迟:slave_io_running为no时值为null(复制中断)、并行复制下长期为0但relay log已积压、主从时钟不同步导致跳变或负数、gtid模式下无法反映真实执行进度;必须改用心跳表时间差(如mysql_slave_heartbeat_delay_seconds)结合线程状态和持续时间(for: 2m)进行可靠告警。

Seconds_Behind_Master为什么不能直接告警?
它经常是 NULL 或 0,不代表没延迟,而是指标失效了。常见原因包括:
• Slave_IO_Running: No 时,Seconds_Behind_Master 就是 NULL —— 从库根本收不到 binlog
• 启用了并行复制(slave_parallel_workers > 0)或 binlog_order_commits=OFF,该值长期为 0,但 relay log 积压可能已上千 MB
• 主从系统时间不同步,导致值跳变甚至负数
• GTID 模式下,它不反映 GTID 执行进度,只比对 relay log 末尾事件时间戳,漏掉网络传输、磁盘刷写、大事务阻塞等真实延迟
用 mysqld_exporter 抓心跳表延迟才靠谱
必须绕过 Seconds_Behind_Master,改用主库写、从库读的时间戳差值。实操要点:
• 在主库建心跳表:CREATE TABLE monitor.heartbeat (ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)
• 每秒用 REPLACE INTO monitor.heartbeat VALUES () 更新(避免锁表,用 REPLACE 或 INSERT ... ON DUPLICATE KEY UPDATE)
• 在 mysqld_exporter 的 queries.yaml 中定义自定义查询:
mysql_slave_heartbeat_delay_seconds:<br> query: "SELECT UNIX_TIMESTAMP() - UNIX_TIMESTAMP(ts) FROM monitor.heartbeat"<br> metrics:<br> - metric: mysql_slave_heartbeat_delay_seconds<br> value: 0
• 启动
mysqld_exporter 时加参数:--config.my-cnf=/path/to/exporter.cnf --collect.custom.query,确保加载该文件告警规则必须带状态过滤和持续时间
光看延迟数值会误报。比如主库批量导入时延迟冲到 30s,2 秒后回落,这种毛刺不该触发告警。
• 告警表达式要同时检查复制线程状态:mysql_slave_heartbeat_delay_seconds > 30 and mysql_slave_io_running == 1 and mysql_slave_sql_running == 1
• for: 2m 是底线,短于这个时间的波动一律忽略
• 避免用 mysql_slave_seconds_behind_master 这个默认指标——它就是 Seconds_Behind_Master 的直译,不可靠
• 如果从库有多个 channel(多源复制),需在 PromQL 中用 label 如 {channel="ch1"} 区分,否则聚合会掩盖单个通道异常
mysqld_exporter 权限和采集超时容易漏配
权限不对或超时太短,会导致指标缺失但日志里只显示 context deadline exceeded,误以为是网络问题。
• MySQL 账号至少需要:SELECT on monitor 库(心跳表)、REPLICATION CLIENT(查复制状态)、PROCESS(查连接数)
• mysqld_exporter 启动命令中,--web.listen-address="0.0.0.0:9104" 要配,否则 Prometheus 从远端采集失败
• Prometheus 的 scrape_timeout 必须 ≥ 15s,尤其开了 --collect.perf_schema.events_statements 等重查询收集器时
• 不要用 root 账号跑 exporter;也不要把 exporter 用户授权给 % 却不设防火墙白名单
真实延迟永远藏在心跳时间差里,而不是 SHOW SLAVE STATUS 的某一行字段里。只要心跳表更新频率够高(≤1s)、查询路径够短(单表无 join)、exporter 权限和超时配对,这个延迟值就能反映从库“此刻到底慢了多少”。其他所有优化——比如调大 innodb_log_file_size、关掉 sync_binlog、拆大事务——都得靠这个数字来验证效果。











