Skip to content

CDC 模式 = 遗留数据库的事件化 ​

解决什么问题:遗留数据库的事件流化—— CDC(Change Data Capture)从 DB 事务日志读取变更,避免应用层双写。

业务问题 ​

真实场景 ​

场景 1:从单体迁移到事件驱动

问题:
  - 现有 MySQL 数据库
  - 业务逻辑在应用层
  - 想增加事件流供下游消费
  
反模式(应用层双写):
  def update_order(self, order):
      self.db.update(order)       # 写 DB
      self.event_bus.publish(...) # 发事件
      # 问题:DB 写成功但事件失败 → 不一致
  
正模式(CDC):
  def update_order(self, order):
      self.db.update(order)       # 只写 DB
      # Debezium 监听 binlog → 自动发事件
      # 问题解决:DB 是 SSOT,事件自动生成

Bellemare Ch 4 原话:

"Change Data Capture... A changelog is a record of all changes made to the data of the state store... As a permanent copy of the state maintained outside of the microservice instance, the changelog can be used to rebuild state."

失败模式 ​

失败模式后果
应用层双写DB 与事件不一致
轮询查询高延迟、低效
触发器性能差、难维护

控制论视角 ​

Ch 15:"测量是被控对象状态反馈给控制律的关键环节" + Ch 4 §4.6:"单一真理源"

CDC = 数据库的"测量机制"
  - DB = 被控对象(SSOT)
  - binlog = 测量信号(不可变、连续)
  - 事件流 = 测量的"投影"(物化)
  
优势:
  - 不破坏被控对象
  - 测量是连续的、不可丢失的
  - 测量的延迟可监控

核心概念 ​

CDC 4 模式对比 ​

模式实时性侵入性性能适用
CDC (binlog)实时(ms)低高★ 推荐
Trigger实时高低简单场景
Timestamp Polling准实时中中无 binlog
Dual Write实时高高★ 反模式

CDC 工具对比 ​

工具数据库特点
DebeziumMySQL/PostgreSQL/MongoDB开源、Apache 2.0
AWS DMS多托管、简单
Oracle GoldenGateOracle商业、强大
MaxwellMySQL轻量

CDC 工作流 ​

DB (MySQL)
  ↓ binlog
Debezium Connector
  ↓ 转换为事件
Kafka Topic
  ↓
下游服务

Schema 演进与 CDC ​

挑战:DB schema 改变时 CDC 怎么处理?

方案:
  - Debezium 支持 schema history topic
  - 记录所有 DDL 变更
  - Consumer 可同步 schema

与 IDDD 集成 ​

模式 1:DB 是聚合存储 + CDC 发事件
  应用写聚合 → DB
  CDC 监听 → 发聚合事件
  下游消费 → 物化

模式 2:DB 是聚合存储 + 应用发领域事件
  应用写聚合 → DB
  应用发事件(与 DB 同一事务)
  下游消费

模式 1 是首选(避免双写)。

工程实践 ​

实战 1:Debezium + Kafka + MySQL ​

yaml
# debezium-connector-config.json
{
  "name": "orders-connector",
  "config": {
    "connector.class": "io.debezium.connector.mysql.MySqlConnector",
    "database.hostname": "mysql",
    "database.port": "3306",
    "database.user": "debezium",
    "database.password": "...",
    "database.server.id": "184054",
    "database.server.name": "orders",
    "table.include.list": "orders_db.orders,orders_db.items",
    "tombstones.on.delete": "true",
    "transforms": "route",
    "transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter",
    "transforms.route.regex": "([^.]+)\\.([^.]+)\\.([^.]+)",
    "transforms.route.replacement": "$3"
  }
}

实战 2:避免常见错误 ​

错误 1:把 CDC 当"万能解"
  - CDC 只解决"数据释放"
  - 不解决业务逻辑迁移
  
错误 2:忽略 schema 演进
  - DDL 改变 → Debezium schema history
  - 必须配置
  
错误 3:下游强耦合到 DB schema
  - CDC 事件应转换为业务事件
  - 不应暴露 DB 内部结构

实战 3:监控 CDC 健康 ​

关键指标:
  - binlog 消费 lag
  - 事件发送速率
  - 失败事件数(DLQ)
  - Schema 兼容性状态

反模式 vs 正模式 ​

反模式正模式
应用层双写(DB + 事件)CDC 单写
触发器发事件CDC binlog 监听
轮询查询CDC 实时
暴露 DB schema转换为业务事件

性能指标 ​

指标衡量健康值
CDC 延迟DB 变更 → 事件发出< 1s
事件丢失率丢失事件数 / 总事件0
下游事件覆盖率下游接收事件的比例> 99%
Schema 兼容性schema 演进成功率> 99%

边界判断 ​

何时用 CDC(★ 推荐) ​

  • 遗留系统迁移到事件驱动
  • 需要实时数据流
  • 不想改动现有应用
  • 多下游需要同一数据

何时不用 ​

  • 新建项目(直接用事件)
  • 数据库不支持 binlog
  • 性能瓶颈在 DB(CDC 增加负载)

何时升级 ​

当前升级到触发条件
轮询查询CDC实时性需求
TriggerCDC性能/可靠性
Dual WriteCDC一致性问题

关键洞察 ​

  1. CDC = 数据库的"自然日志"——binlog/WAL 已经是 SSOT 的测量信号。
  2. 避免应用层双写——DB 和事件不一致是分布式系统最大痛点。
  3. DB 是 SSOT,事件是投影——这不是冗余,是不同用途(读写分离)。
  4. Schema 演进必须配套——DDL 改变 → CDC 也要适配。
  5. 与 cybernetics 同构——Ch 15 测量的不可丢失性 = CDC 的 at-least-once 语义。

从名家方法论与工程化思路中蒸馏出自己的工程体系。