MySQL从库relay_log写满磁盘会导致SQL线程报错退出、复制彻底中断;根本原因是relay_log默认与datadir共用分区且不受expire_logs_days控制,需独立监控磁盘并迁移至专用挂载点。

relay_log 写满磁盘后 MySQL 从库直接停止复制
MySQL 从库一旦 relay_log 所在磁盘写满,SQL Thread 会立刻报错退出,复制中断,错误通常长这样:ERROR 1594 (HY000): Relay log read failure: Could not parse relay log event entry 或更直白的 OS error code 28: No space left on device。这不是延迟高,是彻底卡死——连 SHOW SLAVE STATUS 都可能变慢或不可靠,因为 IO 已经濒临瘫痪。
根本原因不是日志太多,而是 relay_log 默认和 datadir 在同一磁盘分区,而主库持续写入、从库 SQL 线程消费慢时,relay_log 文件堆积速度远超预期。
-
relay_log不受expire_logs_days控制,它只靠relay_log_purge=ON(默认开启)配合 SQL 线程推进位置来自动清理 - 只要 SQL 线程停了(比如遇到大事务、DDL、锁冲突),
relay_log就不再被 purge,文件越积越多 - 监控不能只看
datadir使用率,必须单独监控relay_log所在路径的磁盘空间
把 relay_log 移到独立磁盘的实操步骤
最稳妥的做法是把 relay_log 和 relay_log_index 搬离 datadir,放到有足够空间的挂载点(比如 /data/relaylog)。注意:这不是“换路径就完事”,MySQL 启动时会检查并重建索引文件,操作不当会导致复制无法恢复。
- 先停掉从库:
STOP SLAVE;,确认Seconds_Behind_Master为0或已追平 - 记录当前
Relay_Master_Log_File和Exec_Master_Log_Pos(后续验证用) - 修改配置文件,在
[mysqld]下新增两行:relay_log = /data/relaylog/mysql-relay-bin,relay_log_index = /data/relaylog/mysql-relay-bin.index - 确保
/data/relaylog目录存在、属主为mysql、权限为750;不要把旧relay_log文件手动拷过去,MySQL 启动时会自动初始化 - 重启 mysqld,启动后立刻执行
START SLAVE;,再用SHOW SLAVE STATUS\G确认Slave_IO_Running和Slave_SQL_Running都为Yes
为什么不能只靠 expire_logs_days 或定期 flush logs
expire_logs_days 只管 binlog,对 relay_log 完全无效;FLUSH LOGS 会轮转 relay_log,但只是新建一个文件,旧文件是否删除仍取决于 relay_log_purge 和 SQL 线程位置——如果线程卡住,新旧文件一起涨。
- 常见误操作:脚本定时
rm -f /var/lib/mysql/mysql-relay-bin.*—— 这会破坏relay_log_index,导致启动失败或复制错位 -
max_relay_log_size默认 0(即继承max_binlog_size),设太小会导致频繁切换文件,增加索引维护开销;设太大则单个文件撑爆磁盘风险上升 - 真正可控的是
relay_log_space_limit:设为非 0 值(如2G)后,当所有relay_log总大小超限时,IO 线程会主动暂停写入,避免磁盘打满——但它不会自动删日志,只是“踩刹车”
上线后必须验证的三个细节
路径改完不等于万事大吉,MySQL 的行为细节很容易被忽略:
- 检查
SHOW VARIABLES LIKE 'relay_log%';输出中的Value字段,确认路径已生效,且relay_log_purge仍为ON - 观察
SHOW SLAVE STATUS中的Relay_Log_File是否已变成新路径下的文件名(比如/data/relaylog/mysql-relay-bin.000001) - 手动触发一次主库写入(如
INSERT INTO test.t1 VALUES (now());),然后在从库查该记录是否同步成功——别只信Seconds_Behind_Master=0,它有时会假阴性
最麻烦的情况是:你改了路径、重启了,但 Relay_Log_File 还在老目录下。这说明配置没加载(比如写错 section、配置文件路径不对、或被 !include 覆盖),得去 error log 里搜 relay_log 相关警告。


















