4. Debezium深度解析

Debezium 这个项目,说白了就是 CDC 领域的事实标准。我最早接触它是在 2018 年,那时候公司要做 MySQL 到 Elasticsearch 的实时同步,调研了一圈,最后还是选了它。为什么?因为它把最麻烦的 binlog 解析、offset 管理、schema 变更这些事情都封装好了,你只需要关心业务逻辑。

这一章,我会把 Debezium 的核心架构、两种连接器模式,以及后来推出的 Server 模式讲清楚。嗯,都是我在生产环境里踩过坑之后的理解。

Debezium 架构原理

Debezium 本质上是一组 Kafka Connect 的连接器。它利用数据库的日志(比如 MySQL 的 binlog、PostgreSQL 的 WAL)来捕获变更事件,然后把这些事件转换成结构化的消息,推送到 Kafka。

它的核心架构可以分成三层:

  • Connector 层:负责与数据库交互,读取日志,解析事件。每个数据库类型都有自己的 Connector。
  • 转换层:将原始日志事件转换成 Debezium 的通用数据模型,包含 schema、payload、source 元数据。
  • 发送层:通过 Kafka Connect 的框架,将转换后的消息写入 Kafka 指定的 topic。

我画了一张架构图,你可以直观地看到数据是怎么流动的:

Debezium 核心架构图 MySQL / PG binlog / WAL Debezium Connector 解析 + 转换 + 发送 Kafka Topic 说明:Debezium 通过 Kafka Connect 框架运行,Connector 负责从数据库日志中读取变更, 转换成统一格式后写入 Kafka。每个数据库表对应一个 Kafka Topic。

这里有个关键点:Debezium 会记录它读取日志的位置(offset)。如果进程挂了,重启后它会从上次记录的位置继续读取,不会丢数据。我在项目中遇到过因为磁盘写满导致 Connector 挂掉的情况,重启后它自动从断点恢复,一条数据都没丢。这个机制很可靠。

核心要点:Debezium 的 offset 管理是它高可靠性的基石。它把 offset 存储在 Kafka 的 __consumer_offsets 主题或者一个独立的文件中,确保 exactly-once 语义。

Source Connector 与 Sink Connector

Debezium 的连接器分为两类:Source Connector 和 Sink Connector。很多人搞混,我简单说一下。

Source Connector

Source Connector 是 Debezium 的主力。它负责从数据库读取日志,把变更事件推送到 Kafka。目前官方支持的 Source Connector 包括:

连接器名称 支持的数据库 日志类型 生产环境成熟度
Debezium MySQL Connector MySQL 5.7+ / MariaDB binlog ★★★★★
Debezium PostgreSQL Connector PostgreSQL 9.6+ WAL (pgoutput) ★★★★★
Debezium MongoDB Connector MongoDB 3.6+ oplog / Change Streams ★★★★☆
Debezium SQL Server Connector SQL Server 2016+ CDC 表 ★★★★☆
Debezium Oracle Connector Oracle 12c+ LogMiner / XStream ★★★☆☆

配置一个 Source Connector 其实不复杂。我给你看一个 MySQL Connector 的典型配置:

{
  "name": "mysql-connector",
  "config": {
    "connector.class": "io.debezium.connector.mysql.MySqlConnector",
    "database.hostname": "192.168.1.100",
    "database.port": "3306",
    "database.user": "debezium",
    "database.password": "debezium_pwd",
    "database.server.id": "184054",
    "database.server.name": "myapp",
    "database.include.list": "mydb",
    "table.include.list": "mydb.orders,mydb.users",
    "database.history.kafka.bootstrap.servers": "kafka:9092",
    "database.history.kafka.topic": "schema-changes.mydb",
    "include.schema.changes": "true",
    "snapshot.mode": "initial"
  }
}

这里有个坑:database.server.name 这个参数决定了 Kafka topic 的前缀。比如你设成 myapp,那 orders 表的变更就会发到 myapp.mydb.orders 这个 topic。我曾经见过有人把这个名字设成中文,结果 Kafka 直接报错。嗯,记住,只能用字母、数字和下划线。

Sink Connector

Sink Connector 是反向的。它从 Kafka 读取数据,写入到其他系统,比如 Elasticsearch、HDFS、JDBC 数据库等。Debezium 本身不提供 Sink Connector,但 Kafka Connect 生态里有大量的现成实现。

我个人习惯把 Debezium 的 Source Connector 和 Sink Connector 组合使用,形成一条完整的 CDC 管道:

  • Source 端:Debezium MySQL Connector 捕获 binlog 变更,写入 Kafka。
  • Sink 端:Kafka Connect Elasticsearch Sink Connector 从 Kafka 读取数据,写入 Elasticsearch。

这样做的好处是解耦。Source 和 Sink 可以独立扩缩容,互不影响。

小技巧:如果你需要把数据写入多个目标系统,只需要启动多个 Sink Connector 即可。它们可以消费同一个 Kafka Topic,互不干扰。

Debezium Server 模式

传统的 Debezium 必须依赖 Kafka Connect 框架运行。但有些场景下,你不想引入 Kafka,或者你的下游系统不是 Kafka。这时候,Debezium Server 模式就派上用场了。

Debezium Server 是一个独立的 Java 应用,它内置了 Source Connector,可以直接从数据库读取变更,然后通过你指定的 Sink 写入到目标系统。它支持的 Sink 包括:

  • Kafka:写入 Kafka Topic
  • Pulsar:写入 Apache Pulsar
  • Google Cloud Pub/Sub:写入 GCP 消息队列
  • Amazon Kinesis:写入 AWS Kinesis
  • Redis Streams:写入 Redis Stream
  • 文件系统:写入本地文件(JSON 或 Avro 格式)

它的配置方式也很简单。你只需要一个 application.properties 文件:

# Debezium Server 配置示例
debezium.source.connector.class=io.debezium.connector.mysql.MySqlConnector
debezium.source.database.hostname=192.168.1.100
debezium.source.database.port=3306
debezium.source.database.user=debezium
debezium.source.database.password=debezium_pwd
debezium.source.database.server.id=184055
debezium.source.database.server.name=myapp
debezium.source.database.include.list=mydb
debezium.source.table.include.list=mydb.orders

# Sink 配置:写入 Redis Stream
debezium.sink.type=redis
debezium.sink.redis.address=redis://192.168.1.200:6379
debezium.sink.redis.key.format=stream:mydb:orders

启动命令也很直接:

java -jar debezium-server-2.5.0.Final.jar

我在一个 IoT 项目里用过 Debezium Server 模式。当时客户不想用 Kafka,觉得太重了。我就用 Debezium Server 直接把 MySQL 的变更推送到 Redis Stream,前端通过 WebSocket 订阅 Redis,实现了毫秒级的实时数据展示。整个架构非常轻量。

注意事项:Debezium Server 模式虽然方便,但它没有 Kafka Connect 那样的分布式协调能力。如果单机挂了,你需要手动重启。生产环境建议配合容器编排工具(如 Docker Compose 或 Kubernetes)来保证高可用。

最后总结一下:Source Connector 是 Debezium 的核心,负责捕获数据;Sink Connector 负责分发数据;Server 模式则是一个轻量级的替代方案,适合不想引入 Kafka 的场景。你想想看,根据你的业务需求,选择最合适的模式就行。