故障切换时数据到底会不会丢,核心就看一个指标:RPO(Recovery Point Objective,恢复点目标),RPO=0代表不丢数据,RPO大于0则代表容忍丢失最近一段时间内的写入。
很多团队在做容灾方案时,把精力都花在“切换速度”上,盯着RTO不放,结果真出了事故才发现数据丢了,方向完全搞反了,下面把这件事掰开揉碎讲清楚。
先搞清楚RPO和RTO哪个决定数据丢失
不要被RTO带偏节奏
RTO(Recovery Time Objective,恢复时间目标)衡量的是“多久能恢复服务”,它决定你的业务中断多久,RPO衡量的是“恢复到哪个时间点”,它决定你丢多少数据,两者经常被放在一起说,但你要是问一位做灾备的资深工程师,他大概率会告诉你:RPO才是那个真正让你睡不着的数字,服务中断一小时可以解释,数据丢了一小时,那是另一个量级的灾难。
RPO的数值到底在表达什么
业内专家指出,RPO的表达方式很直白:假设你的RPO是5分钟,意味着当主库故障、切换到备库的那一刻,最多会丢失主库最近5分钟内已提交的事务,RPO是10分钟,丢失范围就扩大到10分钟,RPO是0,那就意味着主备之间完全没有数据差只要主库提交成功,备库必须同步确认。
RPO=0和RPO>0的直观区别
- RPO=0:主库生成一笔订单,在给客户端返回“下单成功”之前,这笔事务已经同步到至少一个备节点,主库当场断电,备库顶上,订单还在。
- RPO>0:主库刚收到一笔订单请求,还没来得及同步给备库,机器宕了,备库顶上后,订单查不到,只能靠人工核对或业务补偿。
主从切换丢数据的场景,到底卡在哪个环节
常态同步延迟比故障本身更危险
很多人以为故障切换丢数据,是切换那一下操作错了。绝大多数丢数据事故发生在切换之前主备之间的同步早就滞后了,比如MySQL的主从复制,默认是异步的:主库写入binlog(二进制日志)后就返回成功,从库靠IO线程拉取日志再回放,只要网络抖动、从库负载高、大事务执行慢,从库的延迟就可能从几百毫秒拉到几十秒。
故障切换瞬间的那半秒,数据去了哪里
主库真的宕机时,其实有一个短小的窗口期值得关注:
- 业务请求到达主库。
- 主库写入redo log和binlog,事务在存储引擎层提交。
- 从库还没收到这批binlog日志。
- 主库进程崩溃或服务器断电。
- 集群感知到主库失联,触发切换,从库升主。
第4步启动时,第2步生成的日志就躺在主库的磁盘上,备库其实还不认识它们,如果主库还能抢救一下,这些数据不丢;如果主库直接“壮烈牺牲”,这些就是纯亏的。
半同步复制就保险了吗
半同步复制比异步好一些,它的逻辑是:主库写完binlog后,要等至少一个从库把日志写入relay log(中继日志)并回复ACK,事务才算提交成功,这种机制下,主库返回成功的事务,至少有一个从库有日志,但注意两个坑:
- 如果主库在等待从库ACK的超时时间内(比如默认的50秒)没有收到确认,会退化为异步模式。
- 从库收到了relay log不代表已经回放完成,如果此时从库重启或崩溃,已经relay但未回放的日志可能丢失。
所以在半同步模式下,大概率不丢数据,但依然存在退化窗口和回放窗口的极小概率丢失。
具体排查:查什么日志和指标
自己在环境里验证时,可以按这个路径查:
- 查主库的binlog位点:执行
SHOW MASTER STATUS,记录File和Position。 - 查从库的同步位点:执行
SHOW SLAVE STATUS(MySQL 8.0+是SHOW REPLICA STATUS),看Master_Log_File和Read_Master_Log_Pos,再对比Exec_Master_Log_Pos。 - 算延迟秒数:看Seconds_Behind_Master字段。
- 算真正的数据差距:对比主库binlog的位点和从库实际回放的位点,差的字节数对应多少事务,才是RPO的真实表现。
RPO为0的方案,不只是选对软件的事
多数商用容灾方案的RPO承诺
行业共识认为,要想做到RPO为0,需要完整的同步复制方案,比如存储层同步复制、数据库层的组复制或同步复制模式,很多商业数据库的容灾方案标称RPO=0,原则上没错,但有个前置事实被模糊化了
RPO=0是硬件不坏、网络不脑裂、配置正确的前提下才成立的,误操作删表、软件bug导致的数据损坏,RPO为0的架构帮不了你,那属于数据保护范畴,需要靠备份和时间点恢复来兜底。
实现RPO=0的前提条件
- 主备之间网络必须有足够带宽且极低延迟,同步复制对往返时延非常敏感。
- 业务写入的每个事务都要等待备机确认,对写入性能有明显影响。
- 需要处理“脑裂”场景(两节点互抢主角色),多数方案依赖仲裁机制,仲裁本身也是额外的系统。
- 跨机房场景下,光纤距离越远,时延越高,写性能代价越大。
哪些场景不值得追求RPO为0
- 个人博客、内容网站、内部管理系统:这类数据丢失几分钟甚至几小时都能接受,追求RPO=0纯属浪费预算。
- 高并发写入的电商秒杀系统:全链路同步复制对性能消耗很大,需要与业务层面做权衡,常见做法是核心订单数据走RPO=0方案,非核心日志放宽。
- 已经有完善的数据补偿机制的行业:比如部分互联网金融场景,虽然有RPO=0的基础设施,但业务系统本身有台账、流水、对账体系来兜底。
如何验证你家的故障切换方案真实不丢数据
演练的分层与流程
别等真出故障才验证,按下面这个节奏做故障演练:
- 准备一套与生产配置一致的测试环境,压入真实业务流量,流量不大也可以。
- 制造一个非致命的故障:把主库的网卡断开(模拟网络分区),或直接
kill -9主库数据库进程。 - 观察集群的切换动作,记录切换耗时。
- 在切换结束后,对比主库故障前的binlog位点和新主库实际拥有的日志位点。
切换到新主库后,校验哪些数据点
- 对比新旧主库的binlog位点差,位点差为0,说明日志全同步了。
- 抽查最近时间窗口写入的表:订单表、用户流水表、状态变更记录表,用主键或唯一键进行数据数量统计。
- 如果原主库还能起来,尝试把原主库挂回集群作为从库,观察它恢复期间是否报错,尤其是主键冲突错误这正是原主库存在未同步数据的典型信号。
一个成交场景的实际观察
有一个业务场景很有参考价值订单支付回调,假设主库在19:32:05接收了支付回调并更新订单状态,19:32:07发生宕机,备库在19:32:09完成接替,此时去备库查这笔订单,如果发现状态还是“待支付”,说明这2秒内的事务没有同步过来,RPO≥2秒,如果查到状态已经“已支付”,则这笔业务没有丢失,把类似场景做成自动化检查脚本,每次演练后自动跑一遍,得到真实的RPO采样结果。
Q&A:容灾切换RPO实测常见疑问解答
RPO和RTO是必须同时满足的吗
不是,RPO和RTO是独立定义的两个目标值,需要分别设定,RPO决定你允许丢多少数据,RTO决定你允许中断多久,实际架构设计时,通常先明确RPO(常态数据保护水平),再决定RTO(切换速度和容灾架构复杂度)。
半同步复制下主库宕机还会丢数据吗
可能丢,但窗口极小,如果主库在收到全部从库ACK之前崩溃,且事务没有在任何一个从库上留下relay log,该事务就丢了,还有一种情况:从库收到了relay log但还没来得及回放,从库本身随后也发生故障,这部分日志同样会丢,大多数情况下半同步能满足“接近不丢”的要求,但无法从理论上保证绝对的RPO=0。
如何测出自家系统的真实RPO
建议用“故障注入+日志比对”的手段:在测试环境持续写入数据,随机选择一个时间点模拟主库宕机(直接断电或kill -9),切换完成后对比主备两边的binlog位点和关键表数据,两者取差,重复执行多次,取最大数据差距作为观测到的RPO上限。
故障切换的总原则就一句:把RPO放在首位去选方案,用演练去验证它,别等数据真丢了再回头看指标。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/624199.html





