MySQL主从复制实现crash-safe需按复制模式分别配置:基于binlog位置时,必须设relay_log_info_repository=TABLE、relay_log_recovery=ON,MTS下还需sync_relay_log=1;GTID模式则依赖sync_binlog=1与innodb_flush_log_at_trx_commit=1“双1”配置,并开启relay_log_recovery。

MySQL主从复制要启用crash-safe,关键不是“开个开关”,而是按复制模式(基于binlog位置 or GTID)分别配置一组强一致性参数,否则重启后SQL线程可能重复执行或跳过事务,直接导致数据不一致。
基于binlog文件位置的复制怎么配crash-safe
这种模式下,crash-safe的核心是让SQL线程的执行进度和事务提交原子绑定,避免relay_log.info文件写入滞后于实际执行。
-
relay_log_info_repository = TABLE:必须设为TABLE,这样SQL线程更新位点信息(写入mysql.slave_relay_log_info表)和应用事务被包在同一个InnoDB事务里,要么全成功、要么全回滚 -
relay_log_recovery = ON:MySQL启动时自动丢弃master.info里的旧位点,改从slave_relay_log_info表读取,并重新拉取缺失的binlog,防止relay log被截断或位点错位 - 若启用了MTS(多线程复制),还需加
sync_relay_log = 1:确保每个relay log event写入磁盘后再更新位点,否则Crash恢复时可能无法补齐事务空洞
不设relay_log_info_repository = TABLE,只靠sync_relay_log_info = 1没用——因为OS刷盘和事务提交仍有时间差,crash仍可能发生在“事务已提交但位点未落盘”之间。
基于GTID的复制怎么配crash-safe
GTID模式下,crash-safe依赖的是binlog和InnoDB数据页的严格同步,而不是relay log位点管理。
-
sync_binlog = 1和innodb_flush_log_at_trx_commit = 1:即“双1”配置,保证每个事务的binlog和redo log都强制落盘,崩溃后能通过binlog中的gtid_executed精确还原已执行范围 -
relay_log_recovery = ON:必须开启,否则MySQL可能尝试从损坏/不完整的relay log中解析GTID,导致Retrieved_Gtid_Set不准 - MySQL 5.7+可选
log_slave_updates = OFF:此时GTID执行记录直接写入mysql.gtid_executed系统表(与用户事务一起提交),比写binlog更可靠;但注意:如果从库还要做级联复制,就必须开log_slave_updates
漏掉sync_binlog = 1,哪怕其他都对,crash后也可能丢失最后几个事务的binlog,导致从库无法正确判断哪些GTID该重放。
常见误判:以为开了半同步就等于crash-safe
半同步复制(rpl_semi_sync_master_enabled = 1)解决的是主库crash时的数据丢失问题,它不保护从库自身crash后的状态一致性。
- 主库crash → 半同步能保证至少一个从库收到了binlog,避免主库单点丢失
- 从库crash → 半同步完全不干预,此时靠的还是
relay_log_recovery和位点存储机制是否真正crash-safe - 两者目标不同:半同步保“传输不丢”,crash-safe保“执行不乱”
线上见过太多把半同步当万能药的配置,结果从库重启后报ERROR 1062 (23000): Duplicate entry,就是relay_log_info_repository还设在FILE上。
验证crash-safe是否生效的硬指标
别只看参数,要观察两个关键状态:
- 执行
SHOW SLAVE STATUS\G,确认Relay_Log_Info_File显示的是mysql.slave_relay_log_info(不是relay-log.info文件路径) - 检查
Seconds_Behind_Master非NULL且稳定下降时,手动kill -9 mysqld进程模拟crash,再启服务后:Exec_Master_Log_Pos应严格等于上次正常停止前的值,且无Duplicate entry或No such row类错误 - 如果是GTID模式,
Retrieved_Gtid_Set和Executed_Gtid_Set的差集应在重启后快速收敛,不出现“跳跃式增长”或停滞
真正容易被忽略的点是:crash-safe不是一劳永逸的配置,它依赖整个I/O栈(文件系统、磁盘缓存、RAID卡写缓存)也配合落盘策略。比如开启了innodb_flush_log_at_trx_commit = 1,但RAID卡电池失效导致Write-Back缓存实际没刷盘,照样会丢日志。


















