relay_log占满磁盘是SQL线程卡死后purge机制失效导致的急性中断,非缓慢延迟;必须停SQL_THREAD后清理旧文件或迁移路径,expire_logs_days对其无效。

relay_log 占满磁盘不是“延迟高”导致的缓慢堆积,而是 SQL 线程卡死后,relay_log_purge 机制彻底失效、日志文件持续写入且无法清理的急性故障——必须立刻干预,否则复制直接中断。
SQL 线程卡住,relay_log_purge 就形同虚设
relay_log_purge = ON(默认值)只在 SQL 线程正常推进时起作用:它靠对比 Relay_Log_Pos 和每个 relay log 文件末尾位置,自动删掉已执行完的旧文件。一旦 SQL 线程停摆(比如遇到 DDL 锁、表损坏、主键冲突、GTID 跳过失败),这个判断逻辑就冻结了。
- 常见卡点:
ERROR 1032 (HY000): Can't find record in 'xxx'、ERROR 1594 (HY000): Relay log read failure - 此时
SHOW SLAVE STATUS\G中Slave_SQL_Running: No,但Seconds_Behind_Master可能仍显示数值(缓存值,不可信) -
expire_logs_days对relay_log完全无效——它只管主库的binlog,从库的中继日志不归它管
默认和 datadir 共用分区,主库写不停 + 从库消费不动 = 磁盘秒满
MySQL 启动时不校验磁盘剩余空间,只管往 relay_log_basename 指定路径(默认就是 datadir)里写。主库持续产生 binlog → IO 线程不断拉取 → 新 mysql-relay-bin.000xxx 文件持续生成 → 旧文件又删不掉 → 几小时内就能打爆同一分区。
- 典型错误日志:
OS error code 28: No space left on device -
ls -lh /var/lib/mysql/mysql-relay-bin.* | wc -l常超几百个文件,单个几十 MB 到 GB 不等 - 别指望
FLUSH LOGS能缓解——它对relay_log无任何效果
手动删文件前没停 SQL_THREAD,大概率引发复制错位
只要 SQL_THREAD 还在运行,MySQL 就可能正在读写某个 mysql-relay-bin.000xxx 文件。此时直接 rm,轻则启动报错 Failed to open the relay log,重则 Exec_Master_Log_Pos 指向已删文件,导致后续事件丢失或重复执行。
- 正确顺序只能是:
STOP SLAVE SQL_THREAD;→ 查Relay_Log_File→ 只删编号更小的旧文件 →START SLAVE SQL_THREAD; -
PURGE RELAY LOGS TO 'mysql-relay-bin.000042';是安全替代方案,但它要求relay_log_purge = ON且 SQL 线程未卡死;卡死状态下命令会报错ERROR 1981 (HY000): Cannot purge when relay log is active -
RESET SLAVE会清空所有 relay log 并重置坐标,但会丢弃当前Master_Log_File和Master_Log_Pos,仅适用于确认复制已完全追平且可接受短暂重同步的场景
根治必须迁出 datadir,配置项写错一个字就启不来
把 relay_log 和 relay_log_index 指向独立挂载点(如 /data/relaylog/),是从源头隔离风险的唯一可靠方式。但这不是改完配置重启就行的事——MySQL 启动时会严格校验 relay_log_index 文件是否存在、路径是否可写、内容是否匹配新 relay_log 前缀。
- 操作前必须:
STOP SLAVE;→ 确认Seconds_Behind_Master = 0→ 记下Relay_Master_Log_File和Exec_Master_Log_Pos - 配置必须成对出现:
relay_log = /data/relaylog/mysql-relay-bin和relay_log_index = /data/relaylog/mysql-relay-bin.index,路径结尾不能带斜杠,文件名不能含扩展名 - 千万别手动拷旧 relay log 文件过去——MySQL 启动后会自动初始化新索引,并从上次
Exec_Master_Log_Pos继续拉取
真正容易被忽略的是:卡死的 SQL 线程本身不报错到错误日志里,SHOW SLAVE STATUS 的 Seconds_Behind_Master 字段在卡死后还会缓存旧值,看起来“还在追”,实际早已停摆。查 Slave_SQL_Running 和 Last_SQL_Error 才是第一判断依据。


















