relay log堆积直接卡住sql线程执行,主因是磁盘i/o瓶颈、relay_log_space_limit过小、ssd老化、swap启用、并行复制配置不当及慢查询或mdl锁阻塞。

Relay Log堆积直接卡住SQL线程执行
Relay Log不是“缓存”,而是SQL线程必须逐条读取并执行的指令队列。一旦relay log文件写满、轮转频繁,或磁盘IO跟不上写入节奏,SQL线程就会反复阻塞在Reading event from the relay log或Updating状态——它根本拿不到下一条可执行语句,自然无法推进同步进度。
磁盘I/O瓶颈是最常见的堆积诱因
很多团队把relay_log和datadir放在同一块云盘(比如阿里云ESSD或AWS gp3),结果主库高TPS产生的binlog被IO线程快速写入relay log,而SQL线程又要同时刷InnoDB redo、更新buffer pool、写doublewrite buffer——所有写请求挤在同一物理队列里排队。这时用iostat -x 1会看到%util > 80%、await > 20ms,就是典型信号。
-
relay_log_space_limit设得太小(比如1G)但内存又不足,会强制频繁轮转+fsync,打断SQL线程连续读取 - SSD使用超1年且为消费级型号(如Samsung 970 EVO),磨损后随机写延迟飙升,表现为SQL线程常卡在
Writing to net却无实际网络传输 - 系统
vm.swappiness > 1,内存吃紧时触发swap,relay log读取变成磁盘→swap→内存的三段跳,IO放大数倍
并行复制没开对,反而让堆积更隐蔽
MySQL 5.7+默认启用slave_parallel_type = LOGICAL_CLOCK,但它依赖binlog中事务的last_committed标记。如果主库是单线程写入、或用了binlog_format = STATEMENT + 大量非确定性函数(如NOW()、RAND()),会导致所有事务被串行化到同一个worker线程里——表面看slave_parallel_workers > 0,实际还是单线程重放,relay log照堆不误。
- 检查主库是否开了
binlog_transaction_dependency_tracking = WRITESET(推荐)或COMMIT_ORDER - 确认从库
slave_preserve_commit_order = ON,否则并行worker可能乱序提交,引发一致性风险 -
SHOW PROCESSLIST里如果只看到一个Worker thread在活跃,其他全Waiting for an event from Coordinator,基本就是依赖信息丢失了
慢查询或MDL锁让SQL线程“主动放弃”relay log
从库上跑报表、SELECT ... FOR UPDATE、或未加索引的ALTER TABLE,会持有MDL锁或长时间占用CPU/IO。这时SQL线程不是“读不到日志”,而是读到了,却卡在等待锁释放——SHOW PROCESSLIST里能看到SQL线程状态是Waiting for table metadata lock或Sending data持续几十秒以上。
- 务必开启从库慢查询日志:
slow_query_log = ON、long_query_time = 1 - 避免在从库执行
SELECT COUNT(*) FROM huge_table这类全表扫描 - DDL操作尽量在业务低峰期做,且确认主从表结构一致(否则可能导致SQL线程直接报错中断)
Seconds_Behind_Master数值调参数,不如先看iostat输出和SHOW PROCESSLIST里SQL线程的真实状态。











