知识全景图/ 软件工程与系统/ 数据库生产治理/ 如何设计数据库 CDC、数据同步与派生数据一致性

如何设计数据库 CDC、数据同步与派生数据一致性

不要先背 Kafka 和 Exactly-once;先解释“主库正确,搜索和月报为什么错”

这一页只解决一个问题: 当数据库作为事实源,缓存、搜索、报表宽表这些派生数据怎样不漏、不重、不旧覆盖新,并且错了能重放、能对账、能修回来。
一、事故:主库有账,用户页面没有

用户新增 88 元晚餐。主库事务已经提交,但首页缓存没变,搜索索引搜不到,月报宽表仍是旧金额。客服查主库说“数据在”,用户看页面说“数据没了”。两边都对,因为用户读到的是派生数据。

错误做法为什么会失败逼出的设计
应用写完主库后顺手写缓存、ES、消息主库提交后进程崩溃,下游副作用丢失事实源变化要有可追踪出口
每分钟扫表同步延迟高、易漏更新和删除、扫表重捕获提交后的真实变化
下游错了人工补不知道漏哪段、重哪段、从哪里重放位点、幂等、对账、重放
二、同步设计前只问 6 个问题
问题例子
事实源是哪张表或哪个事件ledger_entries 是事实源,搜索索引不是事实源
下游需要行变更还是业务事件搜索要行变化,预算提醒更适合 LedgerEntryCreated
同步到哪个位点binlog / WAL 的 LSN、Kafka offset、consumer checkpoint
重复事件怎么处理event_id、entry_id + version、处理记录表
乱序事件怎么处理旧 version 不能覆盖新 version,删除墓碑不能被旧更新复活
错了怎么证明和修复主库 vs 索引 / 宽表按用户、月份、entry_id 对账并重放
三、最小可信模型

CDC 不是目的。最小可信模型要同时表达事实、事件、位点和消费结果。

outbox_events - event_id - aggregate_type - aggregate_id - event_type - event_version - payload - source_lsn - created_at consumer_checkpoints - consumer_name - topic - partition_id - offset - source_lsn - updated_at processed_events - consumer_name - event_id - processed_at
吸收点: CDC 解决“变化怎么出来”;Outbox 解决“业务事件和主事务怎么同生共死”;幂等和对账解决“出来以后怎样不写错”。
四、最容易翻车的 4 个边界
边界事故设计动作
重复同一事件重放 3 次,预算重复扣减消费者按 event_id 或 entry_id + version 幂等
乱序金额先改 108 后收到旧事件 98旧版本不得覆盖新版本
删除作废账目仍在搜索和月报里删除 / 作废也要有事件和墓碑语义
全量 + 增量交界新索引漏历史或重复历史记录 snapshot_lsn,全量后从该位点追增量并对账
不要神化工具: Kafka 没积压、CDC 正在跑,只能证明链路在动,不能证明派生数据正确。
五、用 6 个样本证明同步可信
样本通过标准
新增账目后杀掉消费者恢复后从 checkpoint 继续,不漏事件
同一事件重放 3 次搜索、报表、通知结果不重复
更新事件乱序到达旧 version 不能覆盖新状态
作废一笔账搜索、月报、预算都能撤销或排除
重建影子索引历史全量 + 增量追平后和主库对账通过
按 20 分钟窗口重放限速、幂等、差异归零,不制造第二次事故
六、下一步只按分叉位置下钻
如果分叉在读模型
如果分叉在月报口径
如果分叉在导入来源
如果要做同步护栏
总结: CDC 不是工具名,而是派生数据回到事实源的证据链。只要事实源、事件、位点、幂等、版本、删除、全量增量交界、对账和重放说不清,主库正确也挡不住用户看到错误结果。