CDC 与双写是什么
把主库变更同步到搜索、缓存或分析库有两条主路:应用双写实现直接,但一致性要靠补偿与对账;CDC 消费 binlog、oplog 或 WAL 异步投递,不侵入写路径,且天然按变更顺序传递,代价是链路组件更多、重复投递需要幂等消费。选择逻辑大致是:无法改动写代码或变更量大时用 CDC;链路要极简、延迟要求高时双写加对账更直接。两者都建议保留全量重建能力。
基本信息
| 双写 | 写主库成功后写派生存储,失败进补偿队列,靠定时对账兜底 |
|---|---|
| CDC | 用 Debezium 等工具把 binlog、逻辑复制或 change stream 转成事件 |
| 消费要求 | 至少一次投递,按主键做幂等 upsert,删除事件同样要传递 |
| 断点续传 | 保存位点或 resume token,重启后从该点继续 |
| 所属系统 | 数据同步架构通用方案 |
典型使用场景
- 搜索副本:主库写完后把文档同步到搜索集群
- 缓存刷新:数据变更后失效或更新缓存条目
- 数仓入湖:把业务变更投递到分析侧做明细建模
- 异构迁移:新库上线期间双跑并比对数据
- 流处理与审计:把变更事件作为下游计算的输入
订阅变更(结构示意)
订阅变更(结构示意)
const cs = db.orders.watch(); // 订阅集合变更
while (cs.hasNext()) {
const e = cs.next();
upsertIntoSearch(e.documentKey._id, e.fullDocument); // 幂等写入下游
saveResumeToken(e._id); // 保存位点,重启后从令牌继续
}
// 只订阅关心的变更类型
db.orders.watch([{ $match: { operationType: { $in: ["insert", "update", "replace"] } } }]);两条路线对照
| 方式 | 实现方式 | 一致性 |
|---|---|---|
| 双写 | 应用写主库后再写派生存储 | 靠补偿与对账兜底 |
| CDC | 解析日志异步投递 | 顺序可靠,需幂等消费 |
| 时延 | 双写通常更低 | CDC 取决于投递链路 |
| 侵入性 | 需要改动业务代码 | 不改写路径 |
| 运维成本 | 组件少 | 需要维护采集与消息链路 |
选择逻辑:无法改动写代码或变更量大时用 CDC;链路要极简、延迟要求高时双写加对账更直接。
双写不能假设两边同时成功,必须有补偿或对账,否则搜索库与主库会长期不一致。
CDC 消费者不做幂等时,重放与重复投递会造成重复计数或数据放大,幂等键通常用主键加版本号。