4. Debezium MySQL Connector 配置:连接器配置详解、快照模式选择、表包含/排除规则、Decimal 类型处理
好,咱们进入第四章节。前面聊了架构和部署,现在该动手配置连接器了。MySQL Connector 是 Debezium 生态里用得最多的一个,配置项多,坑也不少。我按自己的经验,把最核心的几块拆开讲。
4.1 连接器核心配置详解
一个完整的 MySQL 连接器配置,说白了就是告诉 Debezium 三件事:连哪个 MySQL、监听哪个 binlog、数据往哪发。下面这个配置是我在线上常用的模板:
{
"name": "mysql-connector-orders",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.hostname": "192.168.1.100",
"database.port": "3306",
"database.user": "debezium",
"database.password": "secure_password",
"database.server.id": "223344",
"database.server.name": "prod_orders",
"database.include.list": "orders_db",
"table.include.list": "orders_db.orders, orders_db.order_items",
"database.history.kafka.bootstrap.servers": "kafka1:9092,kafka2:9092",
"database.history.kafka.topic": "schema-changes.orders_db",
"include.schema.changes": "true",
"snapshot.mode": "when_needed",
"decimal.handling.mode": "string",
"tombstones.on.delete": "false"
}
}
这里有几个关键点,我逐个说。
database.server.id 必须唯一。每个连接器实例都要分配一个独立的 server ID,不能跟 MySQL 主从复制的 ID 冲突。我曾经见过两个连接器用了同一个 ID,结果 binlog 解析全乱套了。
database.server.name 是 Kafka topic 的前缀。比如你设成 prod_orders,那生成的 topic 就是 prod_orders.orders_db.orders。命名要规范,我习惯用 环境_业务线 的格式。
database.history.kafka.topic 用来存储 DDL 变更历史。这个 topic 很重要,连接器重启时要靠它恢复 schema 信息。我建议设置 cleanup.policy=compact,保留所有历史版本。
4.2 快照模式选择
快照是连接器启动时对 MySQL 现有数据的全量读取。Debezium 提供了几种模式,选错了会影响业务。
| 模式 | 行为 | 适用场景 |
|---|---|---|
initial |
先做全量快照,再切到 binlog 增量 | 首次部署,数据量不大 |
when_needed |
只在无偏移量时做快照 | 生产环境,支持重启恢复 |
never |
不做快照,直接读 binlog | 已有全量数据,只追增量 |
schema_only |
只快照表结构,不读数据 | 只关心后续变更 |
schema_only_recovery |
恢复 schema 历史,不读数据 | 连接器故障后重建 |
我个人习惯生产环境用 when_needed。为什么?因为首次部署时它会自动做快照,之后重启如果偏移量还在,就直接跳过快照,省时间。但要注意一点——如果数据量很大,快照期间 MySQL 的 IO 会飙升。我遇到过一张 5 亿行的订单表,快照跑了 6 个小时,业务方差点打电话过来。
小技巧:大表快照可以配合 snapshot.fetch.size 参数控制每次读取的行数,默认 2000。我一般调到 5000,但别太大,否则内存容易爆。
4.3 表包含/排除规则
你肯定不想把整个数据库都同步到 Kafka 吧?Debezium 提供了两对过滤规则:
database.include.list/database.exclude.list:按库过滤table.include.list/table.exclude.list:按表过滤
规则是正则表达式,格式为 库名.表名。举个例子:
"database.include.list": "orders_db, inventory_db"
"table.include.list": "orders_db.orders, orders_db.order_items, inventory_db.products"
"table.exclude.list": "orders_db.orders_archive"
这里有个优先级问题:exclude 优先于 include。也就是说,即使某张表在 include 列表里,如果它同时匹配了 exclude,那还是会被排除。我踩过这个坑——当时 include 了 orders_db.*,但忘了排除 orders_db.temp_*,结果一堆临时表的数据全冲到 Kafka 里了。
注意:过滤规则只影响数据变更事件,不影响 schema 变更历史。DDL 还是会记录到 database.history.kafka.topic 里。如果你不想记录某些表的 DDL,得在 MySQL 层面控制权限。
4.4 Decimal 类型处理
Decimal 是 MySQL 里最常用的精确小数类型,但在 Debezium 里处理起来有点绕。默认情况下,Debezium 会把 Decimal 转成 Java 的 BigDecimal,然后序列化成 Kafka Connect 的 org.apache.kafka.connect.data.Decimal 逻辑类型。但问题来了——下游消费者不一定能正确反序列化。
Debezium 提供了三种处理模式:
| 模式 | 输出格式 | 优点 | 缺点 |
|---|---|---|---|
precise |
Connect Decimal 类型 | 精度无损 | 需要自定义反序列化 |
double |
双精度浮点数 | 兼容性好 | 精度丢失,0.1+0.2 可能不等于 0.3 |
string |
字符串 | 精度无损,通用性强 | 下游需要做类型转换 |
我强烈推荐 string 模式。为什么?因为 precise 模式虽然精度高,但下游如果用 Avro 或 JSON Schema,处理起来很麻烦。而 double 模式在金融场景下根本不能用——你想想看,金额字段丢了精度,对不上账怎么办?
配置方式很简单:
"decimal.handling.mode": "string"
这样 Debezium 会把所有 Decimal 字段转成字符串,比如 "123.45"。下游拿到后自己解析成 BigDecimal 或 Decimal 类型,精度完全由你控制。
避坑指南:我曾经在一个支付项目里用了 precise 模式,结果下游 Flink 作业消费时,因为 schema 注册表里的 Decimal 精度定义不一致,导致反序列化失败。后来全部改成 string 模式,问题迎刃而解。记住:在分布式系统里,字符串是最安全的中间格式。
4.5 知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以看到,连接器配置从 MySQL 出发,经过快照、过滤、类型处理三个关卡,最终把干净的数据送到 Kafka。
4.6 实战建议
最后给几个我在生产环境里总结的配置建议:
- 快照期间限流:设置
snapshot.max.threads=1,避免多线程并发读把 MySQL 打满。我见过有人设成 8,结果 IO 直接飙到 100%。 - 监控快照进度:通过 JMX 指标
SnapshotterMetrics可以查看快照完成百分比。这个后面监控章节会细讲。 - Decimal 字段统一规范:如果团队用 Protobuf,建议在 proto 里把 Decimal 字段定义成 string,跟 Debezium 的 string 模式完美配合。
- 测试环境先跑一遍:每次改配置,先在测试环境跑一轮快照,确认过滤规则和类型转换没问题,再上生产。这个习惯救过我很多次。
补充一点:如果你用 snapshot.mode=initial,连接器会在快照开始时记录当前 binlog 位置。快照完成后,从那个位置开始追增量。所以快照期间产生的数据不会丢,但会有短暂延迟。