摘要:两地三中心项目里,数据库的复制模式直接决定切换那天丢不丢数据。本文讲清楚同步、半同步、异步三种模式的真实差距,MySQL / Oracle 各自的落地选择,以及一份切换前可以直接核对的检查清单。
关键词:数据库同步、RPO、两地三中心、容灾切换、半同步复制、MySQL MGR、Oracle Data Guard
一、先讲一次「数据是怎么丢的」
某同城双活项目的切换演练,当天看起来非常成功:流量从 A 中心切到 B 中心,应用正常接管,监控全绿,现场甚至提前收了工。
第二天上午,财务对账报差异:切换时刻前后十几分钟的订单,在新库里查不到。
复盘时把复制链路的状态拉出来看,问题简单得让人后背发凉:
- 那套库用的是异步复制;
- 切换当天正赶上业务高峰,主从延迟已经堆到几十秒;
- 切换脚本里没有「等待追平」这个动作,从库被直接提升为新主;
- 主库上已提交、还没传到从库的那段日志,随着主库一起下线了。
全程没有任何报错。数据库不觉得这是故障——它只是不知道自己不知道。
这件事给我的触动是:RPO 不是写在方案里的一行字,它是复制模式和切换流程共同决定的结果。 方案里写「RPO=5 分钟」很容易,切换那天到底丢不丢数据,看的是链路上每一层的具体配置。
二、三种复制模式,差的不只是延迟
先上对比表,用「一条事务的提交路径」来理解:
| 模式 | 主库什么时候应答客户端 | 极端情况丢多少 | 代价 |
|---|---|---|---|
| 异步复制 | 本地落盘即应答 | 秒级到分钟级 | 几乎零 |
| 半同步 | 至少一个从库确认收到才应答 | 极端情况丢一个事务 | 延迟增加一个网络往返 |
| 全同步 / 组复制 | 多数节点持久化后才应答 | 零丢失(RPO=0) | 吞吐受最慢节点拖累 |
异步复制是所有数据库的默认选项,性能最好。主库把事务写进本地日志就应答客户端,从库「尽力而为」地追。一旦主库故障,没传过去的那部分数据就没了。适合日志类、统计类、丢了能从源头重放的业务。
半同步是折中项:主库提交前,至少要等一个从库确认「日志已收到」。但注意它的语义——极端情况下(比如唯一的从库恰好断开),半同步会退化为异步。所以它承诺的是「把丢失窗口压到极小」,而不是零。
全同步 / 组复制才是 RPO=0 的真正来源:事务必须被多数派节点持久化才算提交,主库故障时从库上必然有一份完整数据。代价是每个事务都要吃一次跨中心网络的往返延迟——这也是为什么它只在**同城裸光纤(1~2ms)**场景里现实,一旦放到异地(几十毫秒),每个事务都多等几十毫秒,吞吐直接崩掉。
一个经常被忽略的认知:RPO=0 的成本单位不是钱,是延迟。物理距离就是 RPO 的天敌。
三、Oracle 和 MySQL 各自怎么落
Oracle:Data Guard 三种保护模式
| 保护模式 | 传输方式 | RPO | 特点 |
|---|---|---|---|
| 最大保护 | 同步(SYNC) | 0 | 灾备端不可用时,主库直接停写 |
| 最大可用 | 平时同步,故障自动降级异步 | 平时 0 | 核心账务的常见选择 |
| 最大性能 | 异步 | 秒级 | 默认,最常见 |
「最大保护」听起来最好,但它把灾备端变成了主库的单点:灾备端一抖,主库就拒绝写入。所以工程上更常见的是「最大可用」——平时同步保零丢失,灾备端故障时自动降级为异步保住主库,恢复后再追平。
MySQL:从主从到 MGR
- 主从 + 增强半同步:多数业务库的甜点位。注意用增强半同步(
AFTER_SYNC,先等从库确认、再本地提交),而不是老的AFTER_COMMIT——前者才是真正的无损语义。 - MGR(组复制):内置 Paxos 类协议,事务要经过组内多数派确认才提交;单主模式下主库故障自动选主,切换不需要人工介入。
- 真实两个 DC 的落地选择:RPO=0 的主通道放在数据库同步层(MGR / RAC Extended 一类),同城裸光纤直连、往返延迟 1ms 级,实测下来 MGR 表现稳定;底层存储的跨中心双活只做兜底。
这里呼应一下前面聊过的取舍(《集中式 vs 分布式存储:数据库场景怎么选》里详细算过账):数据库同步做 RPO=0 主通道、存储双活做兜底。两层都压上同步复制,脑裂窗口和一致性校验成本直接翻倍,多数团队扛不住这个复杂度。
四、选模式之前,先给库分级
不是每个库都值得 RPO=0。
| 业务分级 | 典型系统 | 建议模式 | RPO 目标 |
|---|---|---|---|
| 核心账务 / 交易 | 支付、订单、账务 | 全同步 / 组复制(同城) | 0 |
| 一般业务库 | CRM、运营后台 | 增强半同步 | 秒级 |
| 日志 / 报表 / 缓存 | 行为日志、统计明细 | 异步 | 分钟级,可重放 |
反例也见过:为了「统一标准」给所有库都上组复制,硬件翻倍、运维复杂度翻倍,换来的 RPO 改善对日志类业务毫无意义——它们本来就能从上游重放。
五、模式选对了,切换流程照样能毁掉 RPO
三个关键动作,缺一不可。
1. 等追平,再提升
切换脚本里必须有「复制延迟归零」的判定(MySQL 侧用 GTID 等待,如 WAIT_FOR_EXECUTED_GTID_SET;传统主从看 Seconds_Behind_Master 和中继日志是否回放完)。而且要设超时熔断:追不平就中止切换、转人工,而不是硬切。
2. 先隔离旧主(fencing)
新主提升之前,旧主必须先被断写(置只读、撤 VIP、或集群层面直接隔离)。顺序错了,应用一重连把数据写回旧主,两边数据分叉,这比丢数据更难收场。很多「双活变双主」的事故,根因都是 fencing 没做或者做晚了。
3. 连接路由告诉应用去哪找新主
VIP 漂移、ProxySQL 一类中间件、或者域名切换,三选一。原则是切换时不改应用配置——这件事在《两个数据中心一套 DNS:用 Anycast 把双活流量收敛到一个 IP》里展开过,数据库同样是「认路不认 IP」。
六、一个隐秘的坑:保护性降级
半同步有个「贴心」设计:从库 ACK 超时(默认 10 秒),自动降级为异步,保住主库的可用性。
但换个角度看,这个降级就是 RPO 从秒级悄悄变成分钟级的通道。高峰期网络一抖、从库回放一慢,降级发生了,没有任何人会知道——除非你专门盯着它。
所以半同步架构里,「退化为异步」这个事件本身必须有独立告警。另外这几个延迟来源值得重点盯:大事务(一次批量 DELETE 顶平时十分钟的增量)、批量 DDL、从库回放瓶颈、跨中心链路抖动。
七、切换前检查清单(可直接抄)
| 检查项 | 通过标准 | 风险等级 |
|---|---|---|
| 复制模式 | 与业务分级匹配:核心全同步、一般半同步、日志异步 | 🔴 高 |
| 追平等待 | 切换脚本含延迟归零判定 + 超时熔断 | 🔴 高 |
| 旧主隔离 | fencing 自动化,先隔离旧主、再提升新主 | 🔴 高 |
| 连接路由 | VIP / 中间件 / 域名三选一,切换不改应用配置 | 🟡 中 |
| 降级告警 | 半同步退化异步、复制中断,两者都有独立告警 | 🟡 中 |
| 延迟监控 | 主从延迟阈值告警,高峰期重点盯 | 🟡 中 |
| 演练后对账 | 切换演练收尾固定跑一次核心表对账 | 🟢 低 |
最后一条是教训换来的:开头那次「丢十几分钟订单」,如果演练收尾固定有对账动作,问题当场就能暴露,而不是等财务第二天找上门。
八、写在最后
到这里,容灾系列的四个层面都聊过了:存储层(集中式 vs 分布式怎么选)、数据库层(本文)、应用层(无状态化)、网络层(统一 DNS)。倒过来读也成立:先让业务认路(DNS),再让应用能漂(无状态),数据库跟上(复制模式),存储兜底(双活)。
一句话总结本文:RPO 是设计出来的,不是采购来的。 复制模式选型、切换流程、降级告警,每一环都不能指望「上了双活就万事大吉」。
你遇到过切换后丢数据吗?最后是怎么定位的?评论区聊聊。
(本文为「小树的架构笔记」技术线原创内容,基于真实项目经验与公开架构实践整理,未引用客户交付物。)
本文出自「小树的架构笔记」——两个数据中心云平台的一线运维经验,持续更新。
📎 同名公众号回复【架构】,领《DC 架构实战笔记》(两地三中心 / 存储选型 / DNS 双活 / 无状态化 合集)。「DC 云平台架构实战」系列
- 《两地三中心不是画图:业务系统承载的 3 个真实取舍》
- 《集中式 vs 分布式存储:数据库场景怎么选》
- 《两个数据中心一套 DNS:用 Anycast 把双活流量收敛到一个 IP》
- 《应用无状态化:容灾切换前必须拆掉的第一颗雷》
- 《数据库跨中心同步:切换丢不丢数据,取决于你选的复制模式》(本文)
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/shuye1116/article/details/164507387



