深入理解Flink ---- 系统内部消息传递的exactly once语义

本文介绍了分布式系统中的消息传递语义:AtMostOnce、AtLeastOnce和ExactlyOnce,并详细阐述了Flink如何利用AsynchronousBarrierSnapshotting算法实现ExactlyOnce语义,确保数据处理的一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

At Most once,At Least once和Exactly once

在分布式系统中,组成系统的各个计算机是独立的。这些计算机有可能fail。

一个sender发送一条message到receiver。根据receiver出现fail时sender如何处理fail,可以将message delivery分为三种语义:

 

At Most once: 对于一条message,receiver最多收到一次(0次或1次).

可以达成At Most Once的策略:

sender把message发送给receiver.无论receiver是否收到message,sender都不再重发message.

 

At Least once: 对于一条message,receiver最少收到一次(1次及以上).

可以达成At Least Once的策略:

sender把message发送给receiver.当receiver在规定时间内没有回复ACK或回复了error信息,那么sender重发这条message给receiver,直到sender收到receiver的ACK.

 

Exactly once: 对于一条message,receiver确保只收到一次

 

Flink的Exactly once模式

Flink实现Exactly once的策略: Flink会持续地对整个系统做snapshot,然后把global state(根据config文件设定)储存到master node或HDFS.当系统出现failure,Flink会停止数据处理,然后把系统恢复到最近的一次checkpoint.

什么是分布式系统的global state?

分布式系统由空间上分立的process和连接这些process的channel组成.

空间上分立的含义是,这些process不共享memory,而是通过在communication channel上进行的message pass来异步交流.

分布式系统的global state就是所有process,channel的local state的集合.

process的local state取决于the state of local memory and the history of its activity.

channel的local state是上游process发送进channel的message集减去下游process从channel接收的message的差集.

什么是一致性global state?

假设有两个银行账户A,B.A中初始有600美元,B中初始有200美元. SA, SB, CAB, CBA由A和B分别记录,组成了global state.

在t0时刻,A向B转账50美元;在t1时刻,B向A转账80美元.

如果SA, SB记录于(t0, t1), CAB, CBA记录于(t1, t2),那么global state = 550+200+50+80 = 880,比真实值多了$80. 这就是不一致性global state.

如果 SA, SB, CAB, CBA同属于一个时间区间,那么得到的global state就是一致性的.

Snapshot算法获得一致性global state的难点是什么?

分布式系统没有共享内存(globally shared memory)和全局时钟(global clock).

如果分布式系统有共享内存,那么可以从共享内存中直接获取整个分布式系统的snapshot,无需分别获得各个process,channel的local state再组合成global state.

如果分布式系统有global clock,那么所有的process能在同一时刻各自记录local state,这样就保证了state的一致性.

获得一致性global state的算法 ---- Chandy-Lamport算法

精髓:该算法在普通message中插入了control message – marker

前提:

1)       message的传输可能有delay,但一定会到达

2)       每两个process之间都有一条communication path(可能由多条channel组成)

3)       Channel是单向的FIFO

描述:

Marker sending rule for process Pi

(1)     Process Pi 记录自身state

(2)     Pi在记录自身state后,发送下一条message前,Pi向自己所有的outgoing channel发送marker

Marker receiving rule for process Pj on receiving a marker along channel C

如果Pj第一次接收到marker,那么

         把channel C的state记为空集

         执行marker sending rule

否则(并非第一次接收到marker)

         把记录自身state(或最近一次记录另一个channel的state)后,收到这个marker前的message集记为C的state

 

每个process会记录自身的state和它的incoming channel的state

图解:

A,B,C,D代表4个process.有向线段代表FIFO的channel.绿色圆形代表普通message,橙色矩形代表marker.蓝色的节点和线段代表已经记录state的process和channel

Process A启动snapshot算法,A执行marker sending rule(记录自身state,然后发送marker):

Process B接收到marker,执行marker receiving rule:将channel AB的state记为空集,然后记录自身state并向下发送marker:

 

Process C接收到marker, 执行marker receiving rule:将channel AC的state记为空集,然后记录自身state并向下发送marker:

 

Process D接收到来自于process B的marker, 执行marker receiving rule:将channel BD的state记为空集,然后记录自身state并向下发送marker:

 

 

Process D接收到来自于process C的marker, 执行marker receiving rule:这是process D第二次接收到marker,将channel CD的state记为{5},不会向下发送marker:

自此process A,B,C,D的local state和所有Channel的state都记录完毕. 将这些local state组合,所得到的就是global state

Flink的snapshot算法 ---- Asynchronous Barrier Snapshotting(ABS)

为了消去记录channel state这一步骤,process在接收到第一个barrier后不会马上做snapshot,

而是等待接受其他上游channel的barrier.

在等待期间,process会把barrier已到的channel的record放入input buffer.

当所有上游channel的barrier到齐后,process才记录自身state,之后向所有下游channel发送barrier.

因为先到的barrier会等待后到的barrier,所有所有barrier相当于同时到达process,

因此,该process的上游channel的state都是空集.这就避免了去记录channel的state

图解:

A是JobManager, B C是source,D是普通task.

JobManager发起一次snapshot:向所有source发送barrier.

每个Barrier先后到达各自的source.Source在收到barrier后记录自身state,然后向下游节点发送barrier

Barrier (from)B 到达process D,但不会进行snapshot

Barrier (from)B已经到达process D,

所以当来自于channel BD的record 6 7到达后,process D不会处理它们,而是将它们放入input buffer.

而Barrier (from)C尚未到达process D,所以当来自于channel CD的record 4到达后,process D会处理它.

Barrier C也到达process D.

这样,process D已经接收到了所有上游process的barrier.process D记录自身state,然后向下游节点发送barrier

ABS的at least once模式

当process接收到barrier后,会立刻做snapshot. Process会继续处理所有channel的record.后来的snapshot会覆盖之前的snapshot.

Record 6本不属于这次checkpoint,却包含在process D的local state中.

在recovery时,source认为record 6还没有被处理过,所以重发record 6. 这就导致stream中出现了两个record 6,造成了at least once.

 

这里的问题在于,当第二个barrier到达时,节点D再次对自身做了snapshot.

而在Chandy-Lamport的算法中,第二个barrier到达时,节点D应该对barrier来源的channel做snapshot.

 

对单一input channel的算子来说,没有Alignment这个概念.这些算子在at least once模式下也是呈现exactly once的行为.

 

转载于:https://www.cnblogs.com/tuowang/p/9022198.html

<think>嗯,用户问的是Flink如何保证Exactly-once语义。我需要先回忆一下Flink的相关知识。Exactly-once是流处理中非常重要的特性,确保每条数据只被处理一次,即使在故障恢复时也是如此。 首先,Flink的检查点机制应该是关键。检查点基于Chandy-Lamport算法,定期保存作业状态。每个检查点会插入barrier到数据流中,barrier将流分成不同的窗口,当所有任务都确认状态保存后,检查点才算完成。这样在故障恢复时,可以从最近的检查点重启,保证状态的一致性。 然后,可能需要提到状态后端,比如RocksDB,它支持异步快照,减少对处理性能的影响。不过状态后端具体是存储部分,可能和Exactly-once的实现关系不大,但检查点的持久化存储确实重要。 另外,两阶段提交协议(2PC)在Flink中的应用。比如在连接外部系统(如Kafka)时,Flink通过TwoPhaseCommitSinkFunction实现精确一次输出。这涉及到预提交和提交两个阶段,确保数据要么完全提交,要么回滚,避免部分写入。 还需要区分Exactly-once的不同层次:Flink内部的状态一致性,以及端到端的精确一次。内部通过检查点和恢复机制,而端到端需要外部系统的协同,比如支持事务的Sink。 可能用户需要具体的步骤或流程图说明。比如检查点的触发、barrier对齐、状态快照,故障恢复时的状态回滚和重放数据。这时候分步骤解释会更清晰。 还要注意不同版本的Flink是否有改进,比如在Aligned Checkpoint和Unaligned Checkpoint的区别,后者在反压严重时也能保证生成检查点,但可能会影响Exactly-once的保证吗?不过用户可能不需要这么深入,但可能需要简单提及。 另外,可能用户对Exactly-once和At-least-once的区别有疑惑,可以简要比较,但用户的问题主要关注Exactly-once的实现,所以重点应在Flink的机制。 总结下来,回答的结构应该是:先介绍Exactly-once的重要性,然后分检查点机制和两阶段提交,再讲内部和端到端的保证,可能最后举例说明,比如Kafka到Flink再到Kafka的案例。需要确保用中文,行内公式正确,结构清晰。</think>Flink 通过**分布式快照检查点(Checkpoint)**和**两阶段提交协议(2PC)**的结合实现端到端的 Exactly-once 语义。以下是其核心机制的分步解析: --- ### 一、Checkpoint 机制:保证内部状态一致性 1. **触发检查点** JobManager 周期性触发检查点(如每 10 秒),向 Source 节点插入**特殊标记(Barrier)**到数据流中,将数据流逻辑切分为窗口。 2. **Barrier 对齐** - 每个算子收到 Barrier 后暂停处理后续数据,**先缓存输入流的数据**。 - 当所有输入流的 Barrier 都到达时,算子将当前状态**异步持久化**到可靠存储(如 HDFS/S3)。 - 公式表示状态保存过程: $$ S_i = f(S_{i-1}, D_{window}) $$ 其中 $S_i$ 为第 $i$ 次检查点状态,$D_{window}$ 为当前窗口数据。 3. **恢复机制** 故障时,Flink 回滚到最近完整的检查点,从持久化状态重新处理后续数据,确保状态与数据流完全一致。 --- ### 二、端到端 Exactly-once:两阶段提交协议(2PC) 对于外部系统(如 Kafka、数据库),Flink 通过 **`TwoPhaseCommitSinkFunction`** 实现事务性写入: | 阶段 | 行为 | |---------------------|----------------------------------------------------------------------| | **1. 预提交(Pre-commit)** | Sink 将数据写入外部系统,但标记为**未提交**(如 Kafka 事务未提交)。 | | **2. 提交(Commit)** | 当 Checkpoint 完成时,JobManager 通知所有算子提交事务。 | | **回滚(Rollback)** | 若 Checkpoint 失败,事务自动回滚,外部系统丢弃未提交数据。 | --- ### 三、关键设计优化 1. **精确一次 vs 至少一次** - *Exactly-once*:通过 Barrier 对齐和事务提交确保一致性。 - *At-least-once*:Barrier 不对齐时可能重复处理数据。 2. **反压处理** - **Unaligned Checkpoint**(Flink 1.11+):允许 Barrier 跨越缓存数据,避免反压导致检查点超时。 3. **端到端场景示例** ```text Kafka → Flink → Kafka └── Source 记录消费偏移量(状态) └── Sink 开启 Kafka 事务写入 └── Checkpoint 成功时提交偏移量和事务 ``` --- ### 四、适用场景 - **高一致性要求**:金融交易、计费系统- **高吞吐场景**:Checkpoint 间隔需权衡吞吐和恢复时间。 通过以上机制,Flink 在分布式环境下实现了**状态一致性**和**端到端数据精确处理**,成为流处理领域的核心优势之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值