Apache Flink 是一个开源的流处理和批处理框架,它提供了一种称为“精确一次”(Exactly-Once)语义的数据一致性保证机制,确保数据在发生故障或重试时仅被处理一次。以下是Flink实现精确一次语义的主要技术手段:
-
状态管理与一致性检查点:
- Flink通过一致性的分布式快照(Consistent Checkpoints)来保存所有任务的状态信息。当开启检查点功能时,Flink会周期性地生成全局的一致性快照,这个过程是原子的,即在某一时刻所有并行任务的状态都被冻结,并持久化到可靠的存储中(如HDFS、S3等)。这样,如果发生故障,系统可以从最近的一个成功完成的检查点恢复执行,而不会重复处理任何已处理过的数据。
-
两阶段提交(Two-phase commit, 2PC) :
- 在将结果输出到外部系统(如Kafka、数据库或其他Sink)时,为了实现精确一次语义,Flink引入了两阶段提交协议。在sink操作符中使用
TwoPhaseCommitSinkFunction接口或内置支持两阶段提交的Sink。 - 第一阶段:事务开始时,sink会为每个待写入的目标分区发起预提交请求,记录下需要写入的事件。
- 第二阶段:如果所有预提交成功,那么sink会发出正式提交请求;如果有任何失败,则回滚所有预提交的操作,以确保要么所有目标都接收了消息,要么都没有接收到消息,从而达到事务的一致性。
- 在将结果输出到外部系统(如Kafka、数据库或其他Sink)时,为了实现精确一次语义,Flink引入了两阶段提交协议。在sink操作符中使用
-
异步checkpointing与barrier同步:
- Flink的checkpoint过程中涉及到屏障(barriers)的概念。barrier是在数据流中插入的特殊标记,用于划分不同的检查点窗口。当一个barrier到达某个算子时,该算子先将其内部状态快照,然后继续传递barrier,直到整个作业的所有算子都完成了状态的快照并传递了barrier。这种机制可以确保在一个检查点内所有的数据都被正确地包含进去。
-
幂等性Sink:
- 对于不直接支持两阶段提交的Sink,Flink要求Sink具有幂等性,即多次写入相同数据不会导致结果的不同。例如,在某些场景下,可以利用数据库的事务特性或者消息队列的消息唯一标识(如Kafka的offset)来保证写入操作的幂等性。
-
故障恢复策略:
- 当系统出现故障时,Flink会从最后一个成功的检查点恢复作业,根据检查点中的状态信息以及checkpoint barrier的位置信息,重新消费上游源数据或者重放之前缓存的未提交状态变更,从而避免数据丢失和重复处理。