目录
Flink 中的“至少处理一次”(At-Least-Once)语义
4.2 实现类:TwoPhaseCommitSinkFunction
Flink 中的“至少处理一次”(At-Least-Once)语义
1. 核心定义
“至少处理一次” 是指在发生故障时,数据元素(或事件)不会被丢失,但有可能被处理多次。
这意味着,在系统从故障中恢复后,为了保证不丢数据,某些在故障前可能已经处理过的数据会被重新处理。这是“不丢失”和“高性能”之间的一种权衡。
2. 实现机制:分布式快照与检查点
Flink 主要通过其检查点机制 来实现“至少处理一次”。
- 检查点: Flink 会周期性地为整个应用状态创建一个一致的、全局的“快照”(Snapshot),并将其存储到持久化的存储系统(如HDFS、S3)中。这个快照包含了所有算子在那个时间点的状态。
- 故障恢复: 当发生故障(如机器宕机、网络中断)时,Flink 会:
- 停止所有计算任务。
- 从最近一次成功完成的检查点恢复所有算子的状态。
- 重新启动所有计算任务,并从数据源中指定的位置(通常是与检查点关联的位置)重新开始消费数据。
3. 为什么会导致“重复处理”?
关键在于数据源的重放位置和算子的状态恢复如何协调。
- **“恰好处理一次”** 需要精确的协调:数据源重置到检查点创建时的精确位置,同时算子状态也回滚到那个点。这需要外部系统(如Kafka)支持事务性提交,实现两阶段提交协议。
- **“至少处理一次”** 在实现时,数据源的重放位置可能早于算子状态恢复的位置。
- 例如,一个检查点在第N秒创建。故障后,数据源(如Kafka)被重置到第N秒的位置重新发送数据,但某个算子的状态可能恢复到了稍晚于第N秒的状态(由于异步屏障等实现细节),这就导致从第N秒到该状态点之间的数据被再次处理,从而产生重复。
简单来说,在“至少处理一次”的设置下,Flink 的检查点保证了状态的一致性,但不保证输出到外部系统(如下游数据库、消息队列)的精确性,可能会出现多次写入。
4. 相关概念:自动重启策略
“至少处理一次”语义通常与 Flink 的故障重启策略 结合使用。当作业失败时,重启策略(如固定延迟重启、故障率重启)会控制作业自动重启,并从最近的检查点恢复,从而实现高可用性,这也是“至少处理一次”的保障基础。
5. 与“恰好处理一次”的区别
| 特性 | 至少处理一次 | 恰好处理一次 |
|---|---|---|
| 核心保证 | 不丢,但可能重复 | 不丢,不重,精确一次 |
| 性能开销 | 相对较低 | 较高(需要分布式事务、两阶段提交等) |
| 端到端保证 | 通常只在 Flink 内部保证。输出到外部系统时,需外部系统支持幂等写入才能实现“Exactly-Once”。 | 需要数据源和外部接收器都支持事务(如 Kafka),配合两阶段提交协议,实现真正的端到端精确一次。 |
| 适用场景 | 对重复数据不敏感的场景,或下游可做幂等处理的场景(如统计访问量,重复+1不影响最终趋势)。 | 对数据准确性要求极高,且重复会产生严重影响的场景(如金融交易、精确计数)。 |
6. 简单示例
假设你有一个计算单词频率的 Flink 作业。输入流是 [“a”, “b”, “a”]。
- 在“恰好处理一次”语义下,无论发生多少次故障恢复,最终结果一定是
{a: 2, b: 1}。 - 在“至少处理一次”语义下,如果故障发生在处理第二个
“a”之后、但检查点完成之前,恢复后数据会从“b”或更早开始重放。最终结果可能是{a: 3, b: 2}或{a: 2, b: 2}等。数字是正确的(因为包含所有数据)或更大的(因为包含重复),但绝不会更小。
总结
Flink 的“至少处理一次”语义是一种强一致性、高性能的容错模型。它保证状态不丢失,但不保证输出端(Sink)不重复。在大多数实际应用中,如果下游系统支持幂等写入(例如,基于唯一键的 UPSERT),那么“至少处理一次”语义就能以更低的开销,在效果上达成“恰好处理一次”。
Flink 的恰好处理一次(Exactly-Once)语义
1. 核心定义
恰好处理一次是Flink中最严格的语义保证,它确保:
-
无数据丢失:即使在故障发生时
-
无数据重复:每个事件只被精确处理一次
-
状态一致性:最终结果与无故障情况下的结果完全相同


306

被折叠的 条评论
为什么被折叠?



