订阅更新

Exactly-Once语义:端到端不丢不重的完整链路

Flink 实时计算 20 天 · 第 6 讲 进阶 约 5 分钟读完

三种语义 · 两阶段提交 · 端到端保证 · Kafka事务

本文目录
  1. 📋 面试题
  2. 三种语义
  3. Flink内部的Exactly-Once
  4. 端到端Exactly-Once
  5. 面试加分提示
  6. 📌 总结

📋 面试题

Flink怎么保证Exactly-Once?端到端的Exactly-Once是怎么实现的?

💡 先想30秒,再往下看答案


三种语义

语义 含义 Flink支持
At-Most-Once 最多处理一次,可能丢 不开Checkpoint
At-Least-Once 至少一次,可能重复 Checkpoint + 非对齐Barrier
Exactly-Once 恰好一次,不丢不重 Checkpoint + Barrier对齐

面试关键:Flink内部通过Checkpoint+Barrier对齐就能保证Exactly-Once。但端到端的Exactly-Once还需要Source和Sink的配合。

Flink内部的Exactly-Once

DAY5讲过,Checkpoint做Barrier对齐时,所有上游Barrier到齐后才做快照。这保证了State的一致性。

故障恢复时:回退到最近的Checkpoint → Source从保存的offset重新消费 → State恢复到快照时刻 → 重新计算。

这个过程中数据会被重新处理,但因为State也回退了,所以最终结果等价于每条数据只处理了一次。

端到端Exactly-Once

环节 要求 实现方式
Source 可重放 Kafka(可回退offset)
Flink内部 一致性快照 Checkpoint + Barrier对齐
Sink 幂等写入或事务写入 两阶段提交 / 幂等写

Sink是最难的一环。如果Sink在Checkpoint之后、下次Checkpoint之前写了数据然后任务挂了,恢复后会重复写。

两阶段提交(2PC)

阶段一:预提交(Pre-Commit)
  Checkpoint触发时,Sink开启事务,数据写入但不可见
  
阶段二:正式提交(Commit)
  Checkpoint成功后,Sink提交事务,数据变为可见

如果Checkpoint失败 → 事务回滚,数据作废

Kafka Sink的两阶段提交

// Kafka Sink开启Exactly-Once
KafkaSink<String> sink = KafkaSink.<String>builder()
    .setBootstrapServers("kafka:9092")
    .setDeliverGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
    .setTransactionalIdPrefix("flink-tx")
    .setRecordSerializer(...)
    .build();

// 注意:Kafka消费端也要设置 isolation.level=read_committed
// 否则消费端能看到未提交的数据,Exactly-Once就失效了

我在做广告归因时用了Kafka→Flink→Kafka链路的Exactly-Once。上线后发现下游消费者没设read_committed,导致消费到了未提交的数据。改了消费端配置后才真正端到端Exactly-Once。

幂等写入(更实用的方案)

很多Sink不支持事务(比如Redis、HBase、大部分OLAP引擎),这时用幂等写入:

幂等 = 同一条数据写多次,结果和写一次一样

实现方式:
  - 用唯一主键覆盖写(Doris/StarRocks的主键模型)
  - UPSERT语义(有则更新,无则插入)
  - 写入前去重(用Redis/布隆过滤器判断是否已写过)

我们写Doris用的就是幂等方案。Doris的Unique Key模型天然支持UPSERT,相同主键自动覆盖。比两阶段提交简单得多,也够用。

面试加分提示

💡 讲清楚内部和端到端的区别:

「Flink内部通过Checkpoint + Barrier对齐保证Exactly-Once。但端到端还需要Source可重放、Sink事务写或幂等写。

Kafka Sink通过两阶段提交实现事务写,但下游消费端必须设read_committed。实际项目中如果Sink支持UPSERT(比如Doris),用幂等写更简单可靠。」

📌 总结

记忆点 内容
三种语义 At-Most-Once / At-Least-Once / Exactly-Once
内部保证 Checkpoint + Barrier对齐
端到端 Source可重放 + 内部Checkpoint + Sink事务或幂等
两阶段提交 预提交(不可见) → Checkpoint成功 → 正式提交
幂等方案 UPSERT/主键覆盖,比2PC更简单实用

▶ 下一篇预告:DAY 7 反压排查


Wood聊大数据 | 9年大数据老兵,聊技术、聊职场、聊成长


小红书正文

Exactly-Once是Flink面试高频题,但很多人只会说「Checkpoint保证」就没了。这最多60分。

关键区别:Flink内部Exactly-Once靠Checkpoint+Barrier对齐。但端到端还需要Source可重放+Sink事务写或幂等写。

Kafka Sink用两阶段提交:Checkpoint触发时开事务写但不可见,Checkpoint成功后提交事务。注意下游消费端要设read_committed,否则Exactly-Once失效。

实际项目中更实用的是幂等写:Doris/StarRocks的主键模型天然UPSERT,相同主键自动覆盖。比两阶段提交简单得多。

刷题进度保存在当前浏览器