bigywater.tech
MySQL / InnoDB · 104

Relay Log 恢复

给一个正在应用relay log的replica真实来一次kill -9,验证relay_log_recovery配置是不是真的能保证崩溃后数据不丢不重。

12754 vs 12965
重启后真实选择的更保守恢复起点
205=205
真实最终两边数据完全一致

做的事:真实往replica写入压力,中途kill -9掉它

代码-- source持续写入200次 for i in 1..200: INSERT INTO t.log (note) VALUES ('burst-i'); -- 真实中途kill -9掉replica进程 kill -9 <replica真实的pid>

验证:真实的崩溃时刻,进程彻底消失

实测 · 本机执行输出
$ ps aux | grep rlr-rep   (真实查不到了,进程被kill -9彻底终止)

source此时真实已经写完全部205行(5条基础数据+200条压力写入)

这次真实是在replica正在"边收边应用"的过程中,粗暴地掐断了它,模拟一次真实的、没有任何优雅关闭机会的崩溃——这时候本地的relay log文件和记录"应用到哪里了"的元数据,真实处于一个不确定是否完整一致的状态。

验证:重启之后,真实没有直接相信旧的位置记录

实测 · 本机重启后的真实错误日志
Starting XA crash recovery... / XA crash recovery finished.

[Warning] Recovery from source pos 12754 and file rs-bin.000001 for channel ''.
Previous relay log pos and relay log file had been set to 12965, ./192-relay-bin.000002 respectively.
这一行真实是本文这次实验里最关键的证据:崩溃前,replica本地记录的"已经应用到relay log的哪个位置"是12965,但重启恢复时,真实选择的起点是12754(source上更早的一个位置)——因为relay_log_recovery=ON这个配置真实让replica不信任自己崩溃前记录的relay log位置(它有可能是不完整写入、或者对应的事务只应用了一半),转而真实回头问source要"最后一个我确定已经完整执行过的GTID对应的位置",从这个更保守、更安全的起点重新拉取和应用,哪怕这意味着直接重复处理一小段已经应用过的数据(靠幂等的行级重放和GTID去重来保证真实不会造成实际问题)。

验证:最终真实的数据结果,一行不多一行不少

实测 · 本机执行输出
source: SELECT COUNT(*) FROM t.log;    → 205
replica(重启恢复后): SELECT COUNT(*) FROM t.log;  → 205   ← 真实完全一致

不管中间经历了怎样真实粗暴的崩溃和恢复过程,最终两边真实的数据完全一致,没有丢失也没有重复——这正是relay_log_recovery加上GTID复制真实共同保证的结果:宁可保守地从更早的位置重新开始,也不冒险直接信任一份可能不完整的本地状态。

分步演示:从真实的kill -9到relay log恢复的完整过程

每一步都是本文上面用真实的崩溃测试跑出来的原始结果。

宁可回退重来,也不信任可能不完整的旧状态
这一步新验证的阶段

    本文用到的工具

    • 本机真实搭建的一主一从复制环境,真实kill -9掉正在应用relay log的replica
    • relay_log_recovery=ON + GTID复制的幂等去重保证
    京ICP备2026067502号-1京公网安备11010502063487号