rpo=0在mysql中必须依赖after_sync半同步复制+sync_binlog=1、innodb_flush_logs_at_trx_commit=1等严格参数协同,因mysqldump/xtrabackup仅为时间点快照,无法覆盖备份间隔内事务,而after_sync确保客户端收到成功响应时binlog已刷盘至至少一个从库。

RPO=0 在 MySQL 半同步复制中不是“自动达成”的结果,而是必须满足一整套严格条件后才可能逼近——主库崩溃时,已返回成功的事务不丢,但前提是你没漏掉任何一个关键配置或状态。
为什么 AFTER_SYNC 是 RPO=0 的硬性分水岭
主库在 COMMIT 前等待从库 ACK,意味着客户端收到成功响应时,该事务的 binlog 已被至少一个从库写入 relay log 并完成 fsync。这一步是 RPO=0 的逻辑锚点。
如果用的是 AFTER_COMMIT(MySQL 5.6 及更早默认),主库先提交再等 ACK,崩溃后从库没收到 binlog 就会丢数据——这种模式下 RPO 必然 > 0。
- 确认当前模式:
SELECT @@rpl_semi_sync_source_wait_point;,必须是'AFTER_SYNC' - 设置方式:
SET GLOBAL rpl_semi_sync_source_wait_point = 'AFTER_SYNC';,仅配置文件里写不生效 - 从库 IO 线程必须重启才能加载新 wait_point:
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
sync_binlog=1 和 innodb_flush_logs_at_trx_commit=1 缺一不可
就算 AFTER_SYNC 生效,如果 binlog 或 redo log 没真正落盘,主库崩溃时仍可能丢失已发往从库的日志——因为主库自己还没刷盘,OS 缓存或磁盘控制器缓存都可能吃掉这部分数据。
-
sync_binlog=1:每次事务提交都强制fsyncbinlog 文件,防止日志滞留在 OS Page Cache -
innodb_flush_logs_at_trx_commit=1:确保 redo log 同步刷盘,这是 InnoDB 持久化的底线 - 两个参数若任意一个为 0 或 2,
AFTER_SYNC就形同虚设——从库有日志,主库自己却没存住,故障切换时无法做一致性校验
半同步不是永远在线,超时降级后 RPO 立即失效
MySQL 半同步会在网络抖动、从库 IO 延迟高、磁盘刷盘慢等情况下自动退化为异步复制,此时 RPO 完全不可控。而这个过程不报错、不中断业务,很容易被忽略。
- 检查是否已降级:
SHOW STATUS LIKE 'Rpl_semi_sync_master_status';返回OFF就说明正在异步复制 - 监控频繁降级:
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_times';值持续增长,说明超时频繁触发 -
rpl_semi_sync_source_timeout(8.0.26+ 为semisync_source_timeout)建议设为 2000ms 而非默认 10000ms,避免长阻塞;但也不能太小,否则轻微抖动就降级 - 从库必须启用
relay_log_recovery=ON,否则重启后 relay log 不完整,ACK 无法重建,半同步长期处于 OFF 状态
主库崩溃后,你真正能依赖的只有“已返回成功的事务”
RPO=0 不代表所有事务都不丢,只保障那些客户端已收到成功响应的事务——未返回前崩溃的事务,即使从库收到了 binlog,主库自己没提交,应用层也收不到确认,需靠幂等重试来兜底。
容易被忽略的一点是:半同步本身不解决从库 relay log 损坏、磁盘故障、或网络中间设备丢包导致 ACK 未送达主库的问题。这些场景下主库可能误判为“未收到 ACK”,从而拒绝提交,造成业务阻塞而非数据丢失——但运维上很难区分是真失败还是假超时。
所以生产环境里,AFTER_SYNC + sync_binlog=1 + innodb_flush_logs_at_trx_commit=1 是底线,而真正的 RPO=0 还得靠稳定低延迟网络、可靠的存储设备、以及对 Rpl_semi_sync_master_status 的实时告警——少盯一眼,就可能在故障瞬间回到异步模式。











