3. Debezium入门:架构、核心组件与部署实战
Debezium 这个名字,你可能会觉得陌生。但说白了,它就是 CDC 领域的事实标准。我最早接触它是在 2018 年,那时候公司要做跨机房数据同步,调研了一圈,最后选了 Debezium。嗯,一用就是好几年。
这一章,我们不讲虚的。直接拆解 Debezium 的架构、核心组件,再给出一份能跑起来的配置。你跟着走一遍,就能在自己的环境里把数据实时抓上来。
3.1 Debezium 整体架构
先看一张图,把 Debezium 的骨架搭起来。
这张图里,我标出了三个关键层次:数据源、Connector 层、以及下游的 Kafka 和 Offset 存储。你仔细看,其实 Debezium 的核心逻辑很简单——监听数据库的 binlog 或 oplog,转成事件流,推给 Kafka。
3.2 核心组件拆解
3.2.1 Connector:数据接入的入口
Connector 是 Debezium 的「耳朵」。它负责跟数据库建立连接,读取变更日志。每种数据库都有自己的 Connector,比如:
- MySQL Connector:基于 binlog,支持 GTID 和 ROW 格式
- PostgreSQL Connector:基于逻辑复制槽(WAL)
- MongoDB Connector:基于 oplog 或 Change Streams
- SQL Server Connector:基于 CDC 表或变更跟踪
3.2.2 Converter:数据格式的翻译官
Converter 负责把 Debezium 内部的数据结构转成你需要的格式。常用的有两种:
| Converter 类型 | 序列化格式 | 适用场景 | 优缺点 |
|---|---|---|---|
| JSONConverter | JSON String | 开发调试、简单消费 | 可读性好,但 Schema 信息丢失 |
| AvroConverter | Avro + Schema Registry | 生产环境、跨团队协作 | Schema 强校验,压缩率高,但依赖 Schema Registry |
我个人习惯,开发阶段用 JSONConverter,方便看数据。上了生产,必须换成 AvroConverter。为什么?因为 Avro 带 Schema,下游消费者能明确知道字段类型,不会出现「这个字段是 String 还是 Long」的扯皮。
3.2.3 Offset:断点续传的命根子
Offset 是 Debezium 的「记忆」。它记录了当前已经读到哪个 binlog 位置了。如果进程重启,Debezium 会从 Offset 记录的位置继续读,保证不丢数据。
Offset 可以存在哪里?
- 文件系统:默认存在
offset.dat文件里,适合单机测试 - Kafka Topic:用
offset.storage.kafka配置,适合生产集群 - 数据库:支持 JDBC 存储,适合已有数据库基础设施的团队
3.3 三种部署模式
Debezium 支持三种部署方式,我分别说说它们的适用场景。
3.3.1 Kafka Connect 模式(最常用)
这是官方推荐的方式。Debezium 作为 Kafka Connect 的一个 Source Connector 运行。你只需要写一个 JSON 配置文件,通过 REST API 提交给 Kafka Connect 集群。
# 启动 Kafka Connect 时加载 Debezium 插件
connect-standalone.sh \
connect-standalone.properties \
mysql-connector.properties
优点:部署简单,支持分布式扩展,自带 REST API 管理。我大部分项目都用这个模式。
3.3.2 Debezium Server 模式
如果你不想用 Kafka,可以用 Debezium Server。它直接把 Change Event 推送到其他消息队列,比如 Pulsar、Kinesis、Google Pub/Sub。
# application.properties 示例
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=cdc_user
debezium.source.database.password=cdc_pass
debezium.sink.type=pulsar
debezium.sink.pulsar.broker.service.url=pulsar://localhost:6650
这个模式适合那些已经用了 Pulsar 或 Kinesis 的团队,不想再引入 Kafka。
3.3.3 Embedded Engine 模式
Embedded Engine 是把 Debezium 直接嵌入到你的 Java 应用里。适合做小规模、定制化的 CDC 场景。
// Java 代码示例
DebeziumEngine<ChangeEvent<String, String>> engine = DebeziumEngine.create(Json.class)
.using(props)
.notifying(record -> {
System.out.println("Key: " + record.key());
System.out.println("Value: " + record.value());
})
.build();
engine.run();
嗯,这个模式我用的不多。除非是边缘场景,比如某个微服务需要监听自己的数据库变化做缓存刷新,否则不建议用 Embedded Engine。维护成本高,出了问题不好排查。
3.4 配置示例:从 MySQL 抓取数据到 Kafka
光说不练假把式。我们直接写一份能用的配置。
# mysql-connector.properties
name=mysql-connector-01
connector.class=io.debezium.connector.mysql.MySqlConnector
database.hostname=192.168.1.100
database.port=3306
database.user=cdc_user
database.password=cdc_pass
database.server.id=184054
database.server.name=myapp
database.include.list=mydb
table.include.list=mydb.orders,mydb.users
database.history.kafka.bootstrap.servers=kafka1:9092,kafka2:9092
database.history.kafka.topic=dbhistory.myapp
include.schema.changes=true
tombstones.on.delete=false
key.converter=org.apache.kafka.connect.json.JsonConverter
value.converter=org.apache.kafka.connect.json.JsonConverter
key.converter.schemas.enable=false
value.converter.schemas.enable=false
offset.storage=org.apache.kafka.connect.storage.FileOffsetBackingStore
offset.storage.file.filename=/tmp/offsets.dat
offset.flush.interval.ms=10000
database.server.name:Kafka Topic 的前缀,比如myapp.mydb.orderstable.include.list:只监听指定表,别全库抓,浪费资源tombstones.on.delete=false:删除操作不生成墓碑消息,减少 Kafka 存储压力offset.flush.interval.ms:Offset 刷盘间隔,太短影响性能,太长可能丢数据
配置写好后,通过 Kafka Connect REST API 提交:
curl -X POST -H "Content-Type: application/json" \
--data-binary @mysql-connector.properties \
http://localhost:8083/connectors
然后你就可以在 Kafka 里看到类似 myapp.mydb.orders 的 Topic 了。消费一下试试:
kafka-console-consumer.sh \
--bootstrap-server kafka1:9092 \
--topic myapp.mydb.orders \
--from-beginning
你会看到类似这样的 JSON 数据:
{
"before": null,
"after": {
"id": 1001,
"user_id": 42,
"amount": 299.00,
"status": "paid"
},
"source": {
"db": "mydb",
"table": "orders",
"ts_ms": 1700000000000
},
"op": "c"
}
op 字段表示操作类型:c 是创建,u 是更新,d 是删除。before 和 after 分别记录变更前后的数据。
key.converter.schemas.enable 和 value.converter.schemas.enable 都设为 false,这样输出的 JSON 不带 Schema 信息,看起来清爽。等调试通了,再改成 Avro 上生产。
3.5 避坑指南
最后,分享几个我踩过的坑:
- MySQL binlog 格式必须设为 ROW:如果用的是 STATEMENT 或 MIXED,Debezium 拿不到完整的数据变更。我曾经接手过一个项目,binlog 格式是 MIXED,结果更新操作只记录了 SQL,没有字段值,根本没法用。
- 数据库用户权限要够:至少需要
SELECT、RELOAD、REPLICATION SLAVE、REPLICATION CLIENT权限。少了任何一个,Connector 启动就会报错。 - Kafka Topic 分区数要提前规划:Debezium 默认每个表一个 Topic,分区数默认 1。如果你的表数据量大,建议提前设好分区数,比如 6 或 12。Topic 创建后再改分区数很麻烦。
- Offset 存储别用文件:前面说过了,生产环境一定要用 Kafka Topic 或数据库存储 Offset。
好了,这一章的内容就到这里。Debezium 的架构和配置其实不复杂,核心就是 Connector 抓数据、Converter 转格式、Offset 记位置。你照着上面的配置跑一遍,应该半小时内就能看到数据流进 Kafka。