mysql如何通过主从延迟监控预防读风险_mysql slave_delay处理

4次阅读

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

mysql如何通过主从延迟监控预防读风险_mysql slave_delay处理

Seconds_Behind_Master 为什么不准?

它只是从库 SQL 线程和 I/O 线程之间的时间差,不是真实业务读写延迟。主库写入快、从库大事务卡住、网络抖动、甚至 relay_log 切换瞬间都会让这个值跳变或归零,但实际数据还没应用完。

  • 真正有风险的是「已写入 relay log 但未执行的 binlog Event」——Seconds_Behind_Master 不反映这部分积压
  • 如果从库正在执行一个耗时 30 秒的大 UPDATESeconds_Behind_Master 可能显示 0,但新读请求会命中旧数据
  • 建议配合 SHOW SLAVE STATUSG 中的 Exec_Master_Log_PosRead_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_runningslave_io_running

这两个状态为 No 时,Seconds_Behind_Master 就完全失效,但很多中间件或应用层仍会把流量打过去。

  • 检查语句必须用 SHOW SLAVE STATUSG,不能依赖 SHOW VARIABLESSHOW PROCESSLIST
  • 只要任一值为 No,应立刻将该从库从读池摘除,而不是等延迟超阈值再处理
  • 注意 mysql 8.0.22+ 引入了 replica_sql_runningreplica_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),而非当作数据不存在处理

延迟不是数字问题,是时间窗口问题:你看到的 2 秒延迟,可能是 2 秒前主库刚提交的一条 INSERT,也可能是 2 秒前开始执行的一个锁表 ALTER。监控得盯住源头,而不是只看仪表盘上的那个数字。

text=ZqhQzanResources