主从延迟真凶不一定是长事务,但长事务大概率是帮凶;根本原因是从库sql线程追不上主库binlog写入速度,长事务会拖慢提交节奏并阻塞relay log回放流水线。

主从延迟真凶不一定是长事务,但长事务大概率是帮凶
MySQL 主从延迟(Seconds_Behind_Master 持续增长)的直接原因是:从库 SQL 线程追不上主库 binlog 的写入速度。长事务本身不直接导致延迟,但它会拖慢主库 binlog 的提交节奏,并在从库回放时“卡住”整个 relay log 流水线——尤其当它独占一个 GTID 或事务组、且后续事务依赖其提交顺序时。
更常见的实际诱因包括:大事务(如未分批的 DELETE/UPDATE)、从库 IO/SQL 线程负载高、网络抖动、从库磁盘 IOPS 不足、主从表结构不一致(触发全表扫描)、或者从库开启了 innodb_flush_log_at_trx_commit=1 但磁盘慢。
用 SHOW PROCESSLIST 和 information_schema.INNODB_TRX 快速抓长事务
登录从库执行以下命令,能立刻看到“正在堵路”的事务:
SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id,
TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec,
trx_query
FROM information_schema.INNODB_TRX
ORDER BY duration_sec DESC
LIMIT 5;
重点关注 duration_sec > 60 且 trx_state = 'RUNNING' 的记录;若 trx_query 为空,说明是空事务(比如只开了事务没执行语句),也要 kill 掉。
-
trx_mysql_thread_id可用于在SHOW PROCESSLIST中定位对应连接,确认是否已僵死 - 如果
trx_query是NULL,但trx_started很早,大概率是应用端未正确 commit/rollback,需查业务代码 - 注意:该查询本身不加锁,但频繁执行可能轻微影响性能,生产环境建议每 30 秒查一次
用 slow_query_log + pt-query-digest 定位真正慢的回放 SQL
从库的慢查询日志(slow_query_log=ON)默认只记录客户端发起的查询,**不记录 SQL 线程回放的语句**。必须显式开启:
- 设置
log_slow_slave_statements=ON(MySQL 5.7+),重启或动态生效(5.7.20+ 支持SET GLOBAL) - 确保
long_query_time设得合理(如0.1),否则大量短耗时回放语句会被过滤 - 慢日志路径由
slow_query_log_file指定,建议单独命名(如/var/lib/mysql/slow-slave.log)避免和主库混淆
采集一段时间后,用 pt-query-digest 分析:
pt-query-digest /var/lib/mysql/slow-slave.log --filter '$event->{fingerprint} =~ m/^update|delete|insert/i' --limit 10
输出中优先看 Query_time 平均值高、且 Rows_examined 大的语句——它们往往缺少索引,或在从库上走了全表扫描(主库有缓存/从库统计信息过期)。
监控必须盯住三个指标,缺一不可
单看 Seconds_Behind_Master 容易误判:它可能为 0,但 relay log 已堆积(Relay_Log_Space 持续涨);也可能显示延迟 30 秒,实际只是某条大事务还没提交完。
-
SHOW SLAVE STATUS\G中的Seconds_Behind_Master:仅反映最后一条已执行事件的时间差,对并行复制(slave_parallel_workers > 0)意义减弱 -
Relay_Log_Space:持续增长说明 IO 线程拉取快、SQL 线程消费慢,问题在从库回放能力 -
Exec_Master_Log_Pos与Read_Master_Log_Pos的差值:若差值大且稳定,说明 IO 线程卡了(查网络、主库 binlog 写满、从库磁盘满)
真正棘手的情况是:这三个指标都“看起来正常”,但业务读从库总超时——这时候得去查 performance_schema.events_statements_history_long,抓最近被 SQL Thread 执行过的语句耗时,因为慢日志可能漏掉 sub-second 级别的毛刺。











