直接看show slave status里的四个关键字段:slave_io_running和slave_sql_running必须同时为yes;seconds_behind_master持续>60即异常;last_sql_error非空表明复制已中断,且该字段仅存在于命令结果中,不写入error.log。

直接看 SHOW SLAVE STATUS 里的哪几个字段
别一上来就翻全文,SHOW SLAVE STATUS\G 输出有 30+ 字段,真正要盯的只有 4 个:Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master、Last_SQL_Error。前两个是布尔开关,必须同时为 Yes;后两个是“症状”——Seconds_Behind_Master 持续 > 60 就算异常,Last_SQL_Error 非空基本等于复制已中断。
常见误判点:
-
Seconds_Behind_Master为NULL不代表“没延迟”,而是Slave_IO_Running已停,连日志都收不到 -
Last_SQL_Error不会写进 MySQL 的全局error.log,只存在SHOW SLAVE STATUS结果里,grep 日志找不到 - MySQL 8.0+ 启用 GTID 或并行复制时,
Seconds_Behind_Master可能长期为0,但实际延迟已在堆积
用 pt-heartbeat 替代 Seconds_Behind_Master
想准确知道“从库到底慢了多少秒”,必须绕开 MySQL 自带的延迟计算逻辑。推荐 pt-heartbeat:它在主库每秒写一条带时间戳的心跳记录,从库读取并比对本地时间,结果不受 binlog 格式、GTID、时钟偏差影响。
部署关键点:
- 心跳表必须建在
InnoDB引擎上,避免 MyISAM 表锁干扰复制线程 - 主库执行
pt-heartbeat --daemonize --update --host=master --user=root --password=xxx --interval=1 - 从库查延迟用
pt-heartbeat --monitor --host=slave --master-server-id=1 --interval=5,--master-server-id必须填对,否则可能读错其他主节点的心跳 - 输出值单位是秒,直接喂给 Prometheus 或脚本判断,阈值建议设为 30 秒(比
Seconds_Behind_Master的 60 秒更敏感)
写告警脚本时避开三个坑
很多脚本跑着跑着就开始狂发告警,不是监控没做好,是逻辑没压住。核心原则:不告瞬时抖动,只告持续异常。
实操要点:
- 用
mysql -N -s -e "SHOW SLAVE STATUS\G"获取无格式输出,避免列头干扰解析 - 提取
Last_SQL_Error用awk '/^ *Last_SQL_Error:/{gsub(/^ *Last_SQL_Error: +/, ""); print}',不能简单awk '{print $2}'——字段顺序在不同 MySQL 版本里会浮动 - 告警触发条件必须是“连续 N 次失败”,比如每 30 秒检查一次,连续 3 次
Slave_SQL_Running≠Yes才发钉钉;单次失败可能是网络闪断 - 账号权限只需
REPLICATION CLIENT,别用root,降低风险
Prometheus 告警规则怎么写才不误报
直接用 mysql_slave_status_seconds_behind_master > 60 配告警,等于把 MySQL 的“估算值”当真指标,90% 的误报都出在这儿。
真实可用的规则要加两层过滤:
- 先确保状态正常:
mysql_slave_io_running == 1 and mysql_slave_sql_running == 1 - 再用 pt-heartbeat 的自定义指标:
mysql_slave_heartbeat_delay_seconds > 30(前提是已通过mysqld_exporter的queries.yaml暴露该指标) - 最后加聚合:用
avg_over_time(mysql_slave_heartbeat_delay_seconds[5m]) > 30,过滤掉秒级毛刺 - 不要只告延迟,对
mysql_slave_io_running == 0和mysql_slave_sql_running == 0单独配严重级告警,这类问题必须人工介入
复杂点在于,pt-heartbeat 表要维护、mysqld_exporter 要配查询、Prometheus 规则要分层——漏掉任意一环,告警就变成噪音。











