根本原因是SQL线程卡住或未运行,导致relay log无法消费和清理;需检查Last_SQL_Error、修复数据一致性,并确保relay_log_space_limit正确配置且生效。

Relay Log 增长过快,根本原因不是“写太快”,而是“没消费完”——SQL 线程卡住、延迟严重或压根没跑,IO 线程却照常接收 binlog 并写入 relay log,旧文件又删不掉,空间自然指数级上涨。
Slave_SQL_Running = No 时 Relay_Log_Space 必然涨
这是最常见也最危险的情况:SQL 线程已停止,但 IO 线程仍在运行。此时 Last_SQL_Error 字段一定非空,典型错误包括:
-
1032(Can't find record):从库数据被误删,回放 DELETE 时找不到行 -
1062(Duplicate entry):主库插入唯一键冲突记录,从库已有该值 -
1452(Cannot add or update child row):外键约束失败,通常因主从数据不一致
别急着 SET GLOBAL sql_slave_skip_counter = 1。跳过一条 event 很可能跳错事务边界,后续更难对齐。优先查 performance_schema.replication_applier_status_by_worker 定位具体失败事务,再修复数据一致性(比如补缺失行、删重复键),最后 START SLAVE。
Seconds_Behind_Master 持续增大但 SQL 线程还在跑
说明 SQL 线程没挂,但在“慢吞吞重放”,常见于:
- 大事务(如单条 UPDATE 影响百万行)在从库执行时间远超主库
- 从库
innodb_lock_wait_timeout设置过小,频繁锁等待超时回滚重试 - 缺少必要索引,导致 WHERE 条件全表扫描,拖慢应用速度
- 从库硬件性能弱于主库(尤其是磁盘随机写能力差)
这种场景下 Relay_Log_Space 会缓慢但持续增长。监控 Relay_Log_Space 和 Exec_Master_Log_Pos 的变化速率比看 Seconds_Behind_Master 更准——后者可能因主库空闲而归零,但 relay log 实际仍在堆积。
relay_log_space_limit 配了但没起作用
这个参数常被误解为“自动清理开关”,其实它只在写新 relay log 前做一次空间检查,且有硬性前提:
- 必须写在
/etc/my.cnf的[mysqld]段并重启 MySQL 才生效;SET GLOBAL不支持动态修改 - 单位是字节,不是 MB 或 GB 字符串:
4294967296是 4GB,写成4G或4096M会导致配置无效 - 仅当 SQL 线程正常运行且 relay log 文件已被完全执行后,MySQL 才会在 rotate 时调用
unlink()删除旧文件;卡住时,哪怕设了 8GB,也会写满报错Got fatal error 1236
确认是否生效:执行 SELECT @@global.relay_log_space_limit;,返回 0 表示未启用。
PURGE RELAY LOGS TO 才安全,BEFORE 很容易翻车
手动清理 relay log 时,PURGE RELAY LOGS BEFORE 依赖时间戳,但 SHOW SLAVE STATUS\G 不提供 relay log 文件生成时间,只给 Relay_Log_File(如 mysql-relay-bin.000123)和 Exec_Master_Log_Pos。用时间判断极易误删未执行完的文件。
正确做法:
- 先执行
SHOW SLAVE STATUS\G,记下当前Relay_Log_File(比如mysql-relay-bin.000123) - 选一个明显更小的编号(如
000110),执行PURGE RELAY LOGS TO 'mysql-relay-bin.000110'; - 该命令只会删编号严格小于
000110的文件,只要000110不等于当前正在写的Relay_Log_File,就绝对安全
真正难的从来不是怎么删,而是删完之后——SQL 线程是否能立刻跟上?如果根本原因(比如大事务、锁冲突、缺失索引)没解决,删完半小时又涨回去。


















