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。

Debezium MySQL Connector 配置核心流程 MySQL 数据库 连接器配置 快照模式选择 表包含/排除规则 Decimal 类型处理 Kafka Topic 配置经过快照、过滤、类型处理三个关卡,最终输出到 Kafka Topic

4.6 实战建议

最后给几个我在生产环境里总结的配置建议:

  • 快照期间限流:设置 snapshot.max.threads=1,避免多线程并发读把 MySQL 打满。我见过有人设成 8,结果 IO 直接飙到 100%。
  • 监控快照进度:通过 JMX 指标 SnapshotterMetrics 可以查看快照完成百分比。这个后面监控章节会细讲。
  • Decimal 字段统一规范:如果团队用 Protobuf,建议在 proto 里把 Decimal 字段定义成 string,跟 Debezium 的 string 模式完美配合。
  • 测试环境先跑一遍:每次改配置,先在测试环境跑一轮快照,确认过滤规则和类型转换没问题,再上生产。这个习惯救过我很多次。

补充一点:如果你用 snapshot.mode=initial,连接器会在快照开始时记录当前 binlog 位置。快照完成后,从那个位置开始追增量。所以快照期间产生的数据不会丢,但会有短暂延迟。