如何通过show slave status命令精确监控MySQL迁移过程中的同步延迟?
- 内容介绍
- 文章标签
- 相关推荐
本文共计968个文字,预计阅读时间需要4分钟。
《别只盯着Seconds_Behind_Master看——它在迁移中大概率不准,甚至可能掩盖真实积压。
为什么 Seconds_Behind_Master 在迁移中不可信
这个字段本质是「SQL 线程执行位置时间戳」和「IO 线程拉取位置时间戳」的差值,不是端到端延迟。迁移常见场景下它会失真:
- 从库
Slave_SQL_Running: No时,它常显示NULL或0,但实际已中断数小时 - 主库空闲、没新 binlog 写入时,它恒为
0,可Retrieved_Gtid_Set远大于Executed_Gtid_Set,说明中继日志堆着没执行 - 启用
slave_parallel_type = LOGICAL_CLOCK(MySQL 5.7+ 默认)后,该值不再反映真实回放进度,仅作参考 - GTID 模式下,主库生成事务快、从库还没拉取,
Seconds_Behind_Master完全不更新
必须盯住的三个 SHOW SLAVE STATUS\G 字段
迁移过程中,每轮检查应优先提取以下三项,它们比 Seconds_Behind_Master 更早暴露问题:
-
Last_IO_Errno和Last_SQL_Errno:非0就代表出错,比如2003(连不上主库)、1032(行不存在)、1062(唯一键冲突) -
Slave_IO_Running和Slave_SQL_Running:任一为No,复制已停,不能只看延迟数值 -
Read_Master_Log_PosvsExec_Master_Log_Pos:差值持续扩大,说明 IO 已拉取但 SQL 回放严重滞后;若两者相等但Seconds_Behind_Master非零,大概率是 GTID 空事务或 auto-position 同步异常
用 Retrieved_Gtid_Set 和 Executed_Gtid_Set 算积压量
GTID 模式迁移必须用这个组合判断真实积压,尤其适用于大事务回放卡顿排查:
- 先在从库执行:
SET @gtid_executed := @@global.gtid_executed; - 查缺失的 IO 位点(主库已发、从库还没收到):
SELECT GTID_SUBTRACT(@gtid_executed, Retrieved_Gtid_Set) AS missing_io; - 查待执行事务数(已收到、但没回放):
SELECT GTID_SUBTRACT(Retrieved_Gtid_Set, Executed_Gtid_Set) AS pending_sql;—— 返回结果是 GTID 字符串,长度越长,积压越重 - 注意:
pending_sql结果为空字符串,才表示 SQL 线程真正追平;光看Seconds_Behind_Master = 0不够
用 pt-heartbeat 补足端到端延迟验证
Seconds_Behind_Master 是协议层指标,pt-heartbeat 是业务层指标——它直接回答“这条数据写完,多久能在从库查到”,对迁移一致性校验更关键:
- 主库写入命令:
pt-heartbeat -D test --update -h master_host --interval=1(每秒更新一次心跳表) - 从库读取并计算延迟:
pt-heartbeat -D test --monitor -h slave_host --master-server-id=101 - 常见坑:
mysql_heartbeat表没设主键会导致从库 SELECT 被锁;主库高频写入时,从库可能因单线程回放慢导致时间戳跳变,建议监控其标准差而非瞬时值 - 迁移后期做一致性校验前,务必确认
pt-heartbeat延迟稳定 ≤ 1s,否则mysqldump导出的数据可能已过期
迁移不是看“有没有在跑”,而是看“哪一步卡住了、卡了多久、影响哪些数据”。SHOW SLAVE STATUS 的字段之间有逻辑依赖,单独看任何一个都容易误判。最危险的情况,是 Seconds_Behind_Master = 0、Slave_SQL_Running = Yes,但 pending_sql 里还躺着几百个 GTID——那说明 SQL 线程正在空转,什么都没执行。
本文共计968个文字,预计阅读时间需要4分钟。
《别只盯着Seconds_Behind_Master看——它在迁移中大概率不准,甚至可能掩盖真实积压。
为什么 Seconds_Behind_Master 在迁移中不可信
这个字段本质是「SQL 线程执行位置时间戳」和「IO 线程拉取位置时间戳」的差值,不是端到端延迟。迁移常见场景下它会失真:
- 从库
Slave_SQL_Running: No时,它常显示NULL或0,但实际已中断数小时 - 主库空闲、没新 binlog 写入时,它恒为
0,可Retrieved_Gtid_Set远大于Executed_Gtid_Set,说明中继日志堆着没执行 - 启用
slave_parallel_type = LOGICAL_CLOCK(MySQL 5.7+ 默认)后,该值不再反映真实回放进度,仅作参考 - GTID 模式下,主库生成事务快、从库还没拉取,
Seconds_Behind_Master完全不更新
必须盯住的三个 SHOW SLAVE STATUS\G 字段
迁移过程中,每轮检查应优先提取以下三项,它们比 Seconds_Behind_Master 更早暴露问题:
-
Last_IO_Errno和Last_SQL_Errno:非0就代表出错,比如2003(连不上主库)、1032(行不存在)、1062(唯一键冲突) -
Slave_IO_Running和Slave_SQL_Running:任一为No,复制已停,不能只看延迟数值 -
Read_Master_Log_PosvsExec_Master_Log_Pos:差值持续扩大,说明 IO 已拉取但 SQL 回放严重滞后;若两者相等但Seconds_Behind_Master非零,大概率是 GTID 空事务或 auto-position 同步异常
用 Retrieved_Gtid_Set 和 Executed_Gtid_Set 算积压量
GTID 模式迁移必须用这个组合判断真实积压,尤其适用于大事务回放卡顿排查:
- 先在从库执行:
SET @gtid_executed := @@global.gtid_executed; - 查缺失的 IO 位点(主库已发、从库还没收到):
SELECT GTID_SUBTRACT(@gtid_executed, Retrieved_Gtid_Set) AS missing_io; - 查待执行事务数(已收到、但没回放):
SELECT GTID_SUBTRACT(Retrieved_Gtid_Set, Executed_Gtid_Set) AS pending_sql;—— 返回结果是 GTID 字符串,长度越长,积压越重 - 注意:
pending_sql结果为空字符串,才表示 SQL 线程真正追平;光看Seconds_Behind_Master = 0不够
用 pt-heartbeat 补足端到端延迟验证
Seconds_Behind_Master 是协议层指标,pt-heartbeat 是业务层指标——它直接回答“这条数据写完,多久能在从库查到”,对迁移一致性校验更关键:
- 主库写入命令:
pt-heartbeat -D test --update -h master_host --interval=1(每秒更新一次心跳表) - 从库读取并计算延迟:
pt-heartbeat -D test --monitor -h slave_host --master-server-id=101 - 常见坑:
mysql_heartbeat表没设主键会导致从库 SELECT 被锁;主库高频写入时,从库可能因单线程回放慢导致时间戳跳变,建议监控其标准差而非瞬时值 - 迁移后期做一致性校验前,务必确认
pt-heartbeat延迟稳定 ≤ 1s,否则mysqldump导出的数据可能已过期
迁移不是看“有没有在跑”,而是看“哪一步卡住了、卡了多久、影响哪些数据”。SHOW SLAVE STATUS 的字段之间有逻辑依赖,单独看任何一个都容易误判。最危险的情况,是 Seconds_Behind_Master = 0、Slave_SQL_Running = Yes,但 pending_sql 里还躺着几百个 GTID——那说明 SQL 线程正在空转,什么都没执行。

