先确认是否真损坏:slave_io_running为no多因主从连接失败,非relay-log损坏;仅当slave_io_running为yes且last_sql_error含relay log read failure等才需怀疑。手动用mysqlbinlog验证解析是否失败。损坏后不可直接rm -f relay-bin.*,否则io线程可能重拉旧日志致事务丢失或重复;reset slave不清除master_log_file/pos,必须配合change master to精准续点;扇区损坏时relay_log_recovery无效,须检查dmesg和smart,硬件故障需换盘重建从库。

确认 relay-log 是否真损坏,而非 IO 失败假象
很多“relay-log 损坏”报警其实是 Slave_IO_Running 为 No 导致的连锁反应,比如主库连不上、binlog 文件被删、网络闪断——此时 Relay_Log_File 里记录的还是旧文件,但根本没新内容写入,mysqlbinlog 解析会报错,误判为损坏。
先执行 SHOW SLAVE STATUS\G,重点看:
-
Slave_IO_Running: No→ 查Last_IO_Error,常见如error connecting to master、Could not find first log file name in binary log index file,这类问题跟 relay-log 无关 -
Slave_IO_Running: Yes但Slave_SQL_Running: No→ 再看Last_SQL_Error,出现Relay log read failure、Invalid replication event或log event entry exceeded max_allowed_packet才值得怀疑 relay-log - 手动验证:用
mysqlbinlog /var/lib/mysql/hostname-relay-bin.000042 | head -20,若报Failed to open file或解析中断,基本确认损坏
relay-log 损坏后为什么不能直接 rm -f 再 start slave
relay-log 不是临时缓存,而是已拉取但未执行的事件容器。损坏后,SQL_THREAD 卡在非法偏移,Relay_Log_Pos 指向坏块内部——此时删掉所有 relay-bin.* 文件并 START SLAVE,MySQL 不会自动重建有效中继日志,反而可能让 IO_THREAD 从错误位置重拉,导致事务丢失或重复执行。
RESET SLAVE 也非万能:它清空 relay-log 和 relay-log.index,但不重置 Master_Log_File 和 Master_Log_Pos(即 IO 线程最新拉到的位置),这才是唯一可信坐标。
- 直接删文件 +
START SLAVE→IO_THREAD可能从mysql-bin.000001开始重拉,跳过大量已传输未执行事件 -
RESET SLAVE后不CHANGE MASTER TO→SQL_THREAD启动时找不到起点,报Could not find first log file name in binary log index file - 必须靠
Master_Log_File和Master_Log_Pos重新锚定 SQL 线程执行起点
安全重置 relay-log 并重定向 SQL 线程
核心是丢弃损坏的 relay-log,但保留 IO 线程已同步到主库的最新位置,让 SQL 线程从此处开始重放——不丢、不重、不跳。
- 停复制:
STOP SLAVE; - 记下可信坐标:
SHOW SLAVE STATUS\G中的Master_Log_File(如mysql-bin.000123)和Master_Log_Pos(如456789) - 清空 relay-log:
RESET SLAVE;(这会删掉所有relay-bin.*和relay-log.index) - 重设 SQL 起点:
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000123', MASTER_LOG_POS=456789; - 启动:
START SLAVE;,检查Seconds_Behind_Master是否下降
注意:RESET SLAVE 不影响 Master_Log_File/Master_Log_Pos,所以后续 CHANGE MASTER TO 才能精准续上。如果从库启用了 GTID,这步要换成 SET GLOBAL gtid_slave_skip_counter = 1 配合 START SLAVE,但仅限单个事务损坏场景。
磁盘扇区损坏时,别信 relay_log_recovery
relay_log_recovery = 1 看似省事:从库重启时自动丢弃损坏 relay-log 并重拉。但它依赖内核层 I/O 错误被 MySQL 正确捕获——而真实扇区损坏往往表现为静默读取错误(silent corruption),relay_log_recovery 无法识别,仍会把坏数据当正常事件重放,最终污染从库表数据。
真正该做的是硬件层确认:
- 查内核日志:
sudo dmesg -T | grep -i "ata\|nvme\|sd\|I/O",找sector、bad block、UNC关键词 - 查 SMART:
sudo smartctl -a /dev/sdX,盯Reallocated_Sector_Ct和Current_Pending_Sector是否 > 0 - 若确认硬件故障,
relay_log_recovery无效,必须换盘 + 重建从库,再跑pt-table-checksum校验数据一致性
扇区损坏不是配置能绕过的,它让任何基于当前 relay-log 的修复都失去意义——你修复的是一份已经不可信的副本。











