1. 课程导入

在实时数据平台建设中,“数据不丢、不重、可对账”往往比“跑得快”更难。很多团队在离线时代已经习惯了 T+1 批处理的对账方式,一旦切换到 Kafka + Flink 的实时链路,就会遇到一个尖锐问题:上游业务库的一条订单变更,经过 CDC 采集、Kafka 传输、Flink 计算、下游写入后,究竟会不会重复?会不会丢失?如果重复,财务口径是否还能对齐?这正是 Exactly-Once 要解决的核心命题。

本课程不是单纯讲 Flink Checkpoint 的配置项,也不是只讲 Kafka 事务 API 的调用方式,而是把 Kafka 与 Flink 放在同一条端到端链路中,讨论“从源到汇”的精确一次语义如何真正落地。第 1 章作为导入,先建立业务价值判断、学习目标、整体框架和实战链路全景,为后续 29 章打下共同语言。

一、Exactly-Once 的业务价值:不是技术炫技,而是口径可信

Exactly-Once 常被误解为“每条消息只处理一次”。更准确地说,它指的是在发生故障恢复后,最终结果与没有发生故障时一致,即端到端结果层面不重不漏。对于实时数仓、风控、营销、账单、库存等场景,这个语义直接决定业务能否信任实时数据。

  • 财务与账单:重复扣款、重复入账会直接造成资金损失,必须保证结果幂等或事务一致。
  • 实时库存:重复扣减会导致超卖,漏扣会导致少卖,Exactly-Once 是库存准确性的底线。
  • 风控与反欺诈:重复事件可能触发误判,漏事件则可能放过风险,要求链路可恢复且结果稳定。
  • 实时大屏与指标:GMV、PV、UV 等指标若重复累计,会误导运营决策,对账成本极高。

因此,Exactly-Once 的业务价值可以概括为三句话:让实时结果可对账、让故障恢复可信任、让下游系统敢消费。它不是一个孤立的 Flink 参数,而是贯穿采集、传输、计算、写入、对账的链路级能力。

二、学习目标:从“知道概念”到“能搭链路、能排障”

完成本课程后,你应当能够独立设计并验证一条 Kafka 到 Flink 再到下游存储的 Exactly-Once 链路。具体目标如下:

  1. 理解 Exactly-Once、At-Least-Once、At-Most-Once 的差异,以及端到端语义的边界。
  2. 掌握 Flink Checkpoint、Barrier 对齐、状态后端与 Kafka 消费位点提交之间的关系。
  3. 掌握 Kafka 事务、幂等生产者、read_committed 隔离级别在 Flink 中的配置方式。
  4. 能够根据下游存储类型选择两阶段提交、幂等写入或事务写入方案。
  5. 能够通过日志、指标、Checkpoint 历史和端到端对账定位重复或丢失问题。
  6. 能够完成一条可演示、可压测、可故障注入的实战链路。
学习建议:不要只记配置项。每学一个参数,都问自己三个问题——它解决哪一段的重复或丢失?故障恢复时它依赖什么状态?如果下游不支持事务,我还能怎么做?

三、课程整体框架:四层递进,从语义到实战

本课程共 30 章,整体按“语义基础 → 组件机制 → 链路集成 → 实战排障”四层递进。第 1 章建立全景,后续章节逐步深入。下面用一张结构关系图展示课程主线与关键对象之间的关系。

Kafka + Flink Exactly-Once 实战链路全景 数据源 MySQL CDC 日志 / 埋点 Kafka Topic / Partition 事务 + 幂等生产者 Flink 计算 Checkpoint / Barrier 状态 + 算子链 下游存储 MySQL / Doris HBase / ClickHouse Exactly-Once 保障机制 Checkpoint 对齐 · 状态快照 · 位点提交 · 两阶段提交 Kafka 事务 · read_committed · 幂等写入 · 对账校验 课程四层递进 语义基础与边界 Kafka / Flink 机制 端到端链路集成 实战压测与故障排障

上图展示了本课程的主线:数据源进入 Kafka,再由 Flink 消费计算,最终写入下游存储;Exactly-Once 保障机制横跨三段,并通过 Checkpoint、事务和幂等写入共同实现。课程四层递进则对应从语义到实战的学习路径。

四、实战链路概览:一条可验证的端到端链路

为了让学习不悬空,本课程会围绕一条贯穿始终的实战链路展开:MySQL 业务库产生订单变更,经 CDC 采集写入 Kafka,Flink 消费后做实时聚合与维表关联,结果写入下游存储,同时保留对账能力。链路中的关键配置如下:

# Flink Exactly-Once 关键配置示例
execution.checkpointing.mode: EXACTLY_ONCE
execution.checkpointing.interval: 30s
execution.checkpointing.timeout: 10min
execution.checkpointing.min-pause: 10s
state.backend: rocksdb
state.checkpoints.dir: hdfs:///flink/checkpoints

# Kafka Source 隔离级别
properties.isolation.level: read_committed
properties.commit.offsets.on.checkpoint: true

# Kafka Sink 事务超时
sink.delivery-guarantee: exactly-once
sink.transactional-id-prefix: order-etl-
sink.transaction.timeout: 15min

这条链路中,任何一个环节配置不当,都会导致端到端语义退化。例如 Source 未使用 read_committed,可能读到未提交事务消息;Sink 未开启事务或幂等,Checkpoint 恢复后可能重复写入;Checkpoint 间隔过长,则故障恢复时回放数据量过大。后续章节会逐一拆解。

五、常见误区与复盘:先建立正确预期

误区一:认为开启 Flink Checkpoint 就等于 Exactly-Once。Checkpoint 只保证 Flink 内部状态一致,端到端语义还取决于 Source 位点提交和 Sink 写入方式。
  • 误区二:认为所有下游都支持事务。实际上 MySQL、Doris、HBase、ClickHouse 的支持程度不同,需要选择两阶段提交、幂等写入或去重表方案。
  • 误区三:忽略 Kafka 事务超时与 Flink Checkpoint 超时的匹配。事务超时过短会导致提交失败,过长会阻塞下游读取。
  • 误区四:只关注不重复,忽略不丢失。At-Least-Once 加幂等写入也能达到结果精确一次,但前提是幂等键设计正确。
  • 误区五:没有对账机制。即使链路配置正确,也需要端到端计数、校验和或业务对账来兜底。