主从延迟高时应优先验证Seconds_Behind_Master的可信度,再结合Exec_Master_Log_Pos与Read_Master_Log_Pos差值、pt-heartbeat工具及事务级监控综合判断,并通过开启并行复制、合理配置参数、避免大事务等手段系统性优化。

主从延迟高时先看 Seconds_Behind_Master 是否可信
这个值在 MySQL 5.7+ 中多数情况下是准确的,但遇到并行复制开启、GTID 开启、或从库 SQL 线程被阻塞(比如卡在锁等待)时,Seconds_Behind_Master 可能长时间显示为 0,实际延迟却在累积。更可靠的判断方式是比对主从的 Exec_Master_Log_Pos 和 Read_Master_Log_Pos 差值,再结合主库 SHOW MASTER STATUS 的当前位置估算字节级延迟。
实操建议:
- 用
SELECT MASTER_POS_WAIT('mysql-bin.000001', 123456789, 10)在从库上主动验证同步点是否已追上(注意超时设置) - 避免只依赖
SHOW SLAVE STATUS\G里的Seconds_Behind_Master做告警阈值,建议配合pt-heartbeat工具做毫秒级延迟探测 - 如果从库
Slave_SQL_Running_State显示Waiting for dependent transaction to commit,说明并行复制被事务依赖关系卡住,不是网络或 IO 问题
从库单线程回放瓶颈:必须开 slave_parallel_workers
MySQL 5.6 默认单线程回放,哪怕主库并发很高,从库也永远追不上。开启并行复制是降低延迟最直接的手段,但要注意版本差异和参数搭配。
实操建议:
- MySQL 5.7+ 推荐用
slave_parallel_type = LOGICAL_CLOCK+slave_parallel_workers = 8~16(根据 CPU 核数设,别超过物理核数) - MySQL 8.0+ 可考虑
slave_parallel_type = DATABASE,但仅当业务写入集中在少数库且库间无强事务耦合时才有效;否则容易因跨库事务退化成单线程 - 开启后务必检查
SHOW PROCESSLIST中是否有多个Worker线程在运行,且Slave_SQL_Running_State不再长期停留在Reading event from the relay log - 注意
slave_preserve_commit_order = ON必须开启,否则并行回放可能破坏事务提交顺序,导致主从不一致
sync_binlog 和 innodb_flush_log_at_trx_commit 不要盲目调低
主库写入性能提升常让人想把 sync_binlog 设成 0 或 1000,把 innodb_flush_log_at_trx_commit 设成 2。这确实能压测跑出更高 TPS,但会显著放大主从延迟风险——因为 binlog 和 redo 日志不同步落盘,从库读到的日志可能是“半截”的,或者主库 crash 后从库无法继续同步。
实操建议:
- 生产环境建议保持
sync_binlog = 1和innodb_flush_log_at_trx_commit = 1,这是保证主从数据一致性的底线 - 若实在扛不住压力,可将
sync_binlog = 1与innodb_flush_log_at_trx_commit = 2组合使用(牺牲主库单点可靠性,换取延迟稳定性),但需确认业务能接受主库宕机丢失最多 1s 事务 - 绝对不要设
sync_binlog = 0,它会让从库读取的 binlog 文件位置滞后于实际写入位置,造成不可预测的延迟跳变
大事务是延迟杀手,监控和拆分比调参更管用
一个执行 30 秒的 UPDATE 或 DELETE,在从库上同样要重放 30 秒,期间所有后续事务都得排队。这种延迟不会因为开多少 worker 就消失,只会越积越多。
实操建议:
- 在主库上定期查
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60,找出长事务源头 - 用
pt-query-digest分析慢日志,重点关注Rows_examined和Rows_affected极高的语句,它们往往是未加 limit 的清理任务或误操作 - 业务侧必须约定:所有影响行数预估超 1 万的 DML,必须走批处理(
LIMIT 1000+ 循环)+ 间隔休眠,不能一把梭 - 从库上临时启用
long_query_time = 1并开启慢日志,能快速定位是不是某个大事务正在拖垮 SQL 线程
真正难处理的延迟,往往藏在「看起来正常」的大事务里——它不报错、不卡死、Seconds_Behind_Master 慢慢涨,等发现时已经落后几小时。监控要盯具体事务,而不是只看那个数字。


















