4、快照模式详解:initial、when_needed、never、initial_only 模式选择与场景

快照(Snapshot)是 Debezium 连接器启动后的第一件事。说白了,就是连接器在正式监听 binlog 之前,先把数据库里已有的数据全量读一遍。这个阶段处理不好,轻则数据不一致,重则把源库压垮。

Debezium 提供了四种快照模式:initial、when_needed、never、initial_only。我见过不少团队因为选错了模式,导致上线后数据对不上,或者连接器频繁重启。今天咱们就把这四种模式掰开揉碎,讲清楚各自适合什么场景。

核心观点: 快照模式没有银弹。选型的关键在于——你的业务能不能接受全量扫描带来的性能冲击?你的数据一致性要求有多高?

4.1 四种模式速览

先看一张对比表,心里有个底:

模式 行为 适用场景 风险点
initial 启动时执行全量快照,之后切到增量 首次部署、数据量可控 大表可能锁表或影响性能
when_needed 只在需要时(如偏移量丢失)自动触发快照 高可用、自动恢复场景 恢复时机不可控
never 跳过快照,直接监听增量 已有全量数据、只关心增量 历史数据缺失
initial_only 只做快照,完成后自动停止 一次性数据迁移 不监听增量

4.2 initial:最常用的默认模式

initial 是 Debezium 的默认模式。连接器启动后,先给所有匹配的表拍一张「快照」,把当前数据全部读出来,写入 Kafka。快照完成后,自动切换到 binlog 监听增量变更。

我个人习惯在首次部署时用这个模式。它保证了你 Kafka 里的数据是完整的——既有历史全量,又有实时增量。但要注意,如果表很大(比如上亿行),快照阶段可能会把源库的 IO 打满。

我的经验: 曾经有个项目,MySQL 里一张表 5 亿行,默认 initial 模式跑起来,数据库 CPU 直接飙到 95%。后来加了 snapshot.fetch.size 参数,把每次抓取行数从默认的 2048 降到 500,才稳住。

配置示例:

{
  "name": "my-connector",
  "config": {
    "connector.class": "io.debezium.connector.mysql.MySqlConnector",
    "snapshot.mode": "initial",
    "snapshot.fetch.size": "500",
    "snapshot.lock.timeout.ms": "30000"
  }
}

这里 snapshot.lock.timeout.ms 也很关键。默认是 10 秒,如果表被其他长事务锁住,快照会超时失败。我建议根据业务峰值调整到 30 秒以上。

4.3 when_needed:自动恢复的救星

when_needed 模式很有意思。它平时不做事,只在连接器发现偏移量(offset)丢失或无效时,才自动触发快照。你想想看,生产环境里 Kafka Connect 重启、Topic 被误删、offset 存储损坏……这些事虽然不常见,但碰上一次就够头疼的。

我曾经在一个金融项目里用过这个模式。当时因为运维误操作清空了 Kafka Connect 的 offset topic,所有连接器都丢了位置。幸好配了 when_needed,它们自动重新做了快照,数据没丢,只是延迟了几个小时。

注意: when_needed 模式依赖 Debezium 内部的 offset 有效性判断。如果你的业务对数据恢复时机有严格 SLA,建议配合 snapshot.delay.ms 参数使用,给数据库一个缓冲时间。

配置示例:

{
  "snapshot.mode": "when_needed",
  "snapshot.delay.ms": "5000"
}

4.4 never:只做增量,历史数据自己搞定

never 模式跳过快照,直接开始监听 binlog。这意味着 Kafka 里只有连接器启动之后的增量数据,之前的历史数据一概没有。

什么场景用?我举两个例子:

  • 你已经通过其他方式(比如 DataX、Sqoop)把全量数据导入了目标系统。 这时候 Debezium 只需要负责增量同步。
  • 你只关心实时变更,不关心历史。 比如监控告警系统,只看当前状态变化。

但这里有个坑:如果连接器重启时 offset 丢了,never 模式不会自动补数据。它只会从当前 binlog 位置开始监听,中间的数据就永远丢了。我曾经因为这个被半夜叫起来过……

避坑指南: 用 never 模式时,一定要确保 offset 存储可靠。建议用 Kafka topic 存储 offset,并且给 topic 设置足够的副本数和 retention。

4.5 initial_only:一次性迁移利器

initial_only 模式只做快照,快照完成后连接器自动停止。它不监听增量,也不维持连接。

这个模式最适合一次性数据迁移场景。比如你要把 MySQL 里的数据全量同步到 Elasticsearch,跑完就完事,不需要持续同步。我有个同事做过一个数据仓库项目,用 initial_only 把 200 多张表一次性同步到 Kafka,然后通过 Kafka Connect Sink 写入 HDFS,整个过程干净利落。

配置示例:

{
  "snapshot.mode": "initial_only",
  "snapshot.max.threads": "4"
}

注意 snapshot.max.threads 参数。默认是 1,也就是单线程扫描。如果你的数据库性能不错,可以调大这个值,加快快照速度。我一般设成 CPU 核心数的一半。

4.6 快照模式选型决策流程

说了这么多,到底怎么选?我画了一张决策图,帮你快速定位:

快照模式选型决策流程 开始选型 是否需要全量历史数据? 是 否 是否需要持续增量? initial 首次部署首选 注意大表性能 是否需要持续增量? 否 initial_only 一次性迁移 完成后自动停止 offset 是否可靠? never 只关心增量 offset 丢失有风险 否 when_needed 自动恢复 适合高可用场景 提示:如果数据库性能敏感,所有模式都建议配合 snapshot.fetch.size 和 snapshot.lock.timeout.ms 使用

4.7 快照参数调优清单

不管选哪种模式,下面这几个参数都值得你关注。我整理了一份清单:

参数名 默认值 我的建议
snapshot.fetch.size 2048 大表降到 500-1000,小表可以提到 5000
snapshot.lock.timeout.ms 10000 生产环境建议 30000-60000
snapshot.max.threads 1 CPU 核心数的一半,不超过 8
snapshot.delay.ms 0 when_needed 模式下建议 5000-10000
snapshot.include.collection.list 全部 只快照需要的表,减少不必要扫描
最后提醒一句: 快照模式不是配完就一劳永逸的。业务增长、数据量变化、数据库负载波动,都可能让你需要重新审视这个选择。我每半年会检查一次生产环境的快照配置,看看有没有优化空间。