Flink Internals - Data Streaming Fault Tolerance(数据流容错)

简介

Apache Flink 提供了一种容错机制来一致地恢复数据流应用程序的状态。该机制确保即使存在故障,程序的状态最终将精确地反映数据流中的每条记录一次。注意,这里有一个开关,将担保降级到至少一次(如下所述)。

容错机制连续绘制分布式流数据流的快照。对于状态小的流应用程序,这些快照非常轻量级,可以频繁地绘制,不会对性能造成很大影响。流应用程序的状态存储在一个可配置的位置(如主节点或HDFS)。

如果程序失败(由于机器、网络或软件故障),Flink将停止分布式流数据流。然后系统重新启动算子,并将它们重新设置为最新的成功检查点。输入流被重置到状态快照的点。作为重新启动的并行数据流的一部分处理的任何记录都保证不属于以前的检查点状态的一部分。

注意:默认情况下,检查点是禁用的。

为了实现这种机制的完全保证,数据流源(如消息队列或代理)需要能够将流回退到定义的最近点。Apache Kafka 有这个能力,Flink 的 Kafka 连接器利用了这个能力。

因为 Flink 的检查点是通过分布式快照实现的,所以我们可以交替使用快照和检查点这两个词。

Checkpointing

Flink 容错机制的核心部分是绘制分布式数据流和操作符状态的一致快照。这些快照充当一致的检查点,在出现故障时,系统可以退回到这些检查点。Flink绘制这些快照的机制在“分布式数据流的轻量级异步快照”中进行了描述。它的灵感来自于分布式快照的标准Chandy-Lamport算法,并特别针对Flink的执行模型进行了调整。

Barriers

Flink 分布式快照的核心元素是流 barriers。这些 barriers 被注入到数据流中,并与记录一起作为数据流的一部分。barriers 永远不会超过记录,它们严格地按顺序流动。barriers 将数据流中的记录分隔为进入当前快照的记录集和进入下一个快照的记录集。每个 barriers 携带快照的ID,快照将快照的记录推到它前面。barriers 不会打断数据流,因此非常轻量级。来自不同快照的多个 barriers 可能同时出现在流中,这意味着各种快照可能同时发生。

流 barrier 被注入流源处的并行数据流。快照n的 barrier 被注入的位置(我们称之为Sn)是源流中快照覆盖数据的位置。例如,在 Apache Kafka 中,这个位置是分区中最后一条记录的偏移量。这个位置的Sn被报告给检查点协调器(Flink的JobManager)。

这些 barrier 随后会顺流而下。当中间算子从它的所有输入流接收到快照n的 barriers 时,它将快照n的 barrier 发送到它的所有传出流。一旦接收算子(流DAG的末端)从其所有输入流接收到 barrier n,它就向检查点协调器确认快照n。在所有接收确认了快照之后,就认为完成了快照。

快照n完成后,作业将不再向源请求来自Sn之前的记录,因为此时这些记录(及其后代记录)将通过整个数据流拓扑。

接收多个输入流的算子需要对齐快照 barrier 上的输入流。上图说明了这一点:

  • 一旦算子从传入流接收到快照 barrier n,它就不能处理来自该流的任何其他记录,直到它也从其他输入接收到 barrier n。否则,它将混合属于 snapshot n 的记录和属于 snapshot n+1的记录。
  • 报告 barrier n 的流被暂时搁置。从这些流接收的记录不会被处理,而是被放入输入缓冲区。
  • 一旦最后一个流接收到 barrier n,算子将发出所有挂起的传出记录,然后发出 snapshot n barrier 本身。
  • 之后,它继续处理来自所有输入流的记录,在处理来自流的记录之前处理来自输入缓冲区的记录。

State

当算子包含任何形式的状态时,该状态也必须是快照的一部分。算子状态有不同的形式:

  • User-defined state:这是由转换函数(如map()或filter())直接创建和修改的状态。
  • System state:这种状态指的是属于运算符计算的一部分的数据缓冲区。这种状态的典型例子是窗口缓冲区,系统在其中收集(和聚合)窗口的记录,直到计算和清除窗口为止。

算子在从其输入流接收到所有快照 barrier 并在将 barrier 发送到其输出流之前对其状态进行快照。此时,barrier 之前的记录对状态的所有更新都已完成,而 barrier 应用之后,依赖于记录的更新将不再发生。因为快照的状态可能很大,所以它存储在可配置的状态后端。默认情况下,这是 JobManager 的内存,但是对于生产使用,应该配置分布式可靠存储(例如HDFS)。在存储状态之后,算子确认检查点,将快照屏障发送到输出流中,然后继续。

结果快照现在包含:

  • 对于每个并行流数据源,在快照启动时流中的偏移/位置
  • 对于每个算子,都有一个指向存储为快照一部分的状态的指针

高清图片地址:https://ci.apache.org/projects/flink/flink-docs-release-1.9/fig/checkpointing.svg

Exactly Once vs. At Least Once

对齐步骤可能会增加流程序的延迟。通常,这种额外的延迟大约是几毫秒,但是我们已经看到一些异常值的延迟明显增加的情况。对于所有记录都需要一致的超低延迟(几毫秒)的应用程序,Flink有一个开关来跳过检查点期间的流对齐。当算子看到来自每个输入的检查点屏障时,检查点快照仍然被绘制。

当跳过队列时,操作人员将继续处理所有输入,即使在检查点n的某些检查点屏障到达之后也是如此。这样,操作人员还可以在获取检查点n的状态快照之前处理属于检查点n+1的元素。在恢复时,这些记录将以重复的形式出现,因为它们都包含在检查点n的状态快照中,并将在检查点n之后作为数据的一部分重新发送。

具有多个前算子(join)和多个发送者(在流重新分区/ shuffle 之后)的算子才会发生对齐。因此,只有并行流操作(map()、flatMap()、filter()、…)的数据流实际上只提供一次保证,即使在至少一次模式下也是如此。

异步状态快照

注意,上面描述的机制意味着算子在将状态快照存储在状态后端时停止处理输入记录。此同步状态快照在每次捕获快照时都会引入延迟。

可以让算子在存储状态快照时继续处理,从而有效地让状态快照在后台异步发生。为此,算子必须能够生成一个状态对象,该对象应该以一种对操作符状态的进一步修改不会影响该状态对象的方式存储。例如,在 RocksDB 中使用的即写即拷数据结构具有这种行为。

在接收到其输入上的检查点 barrier 之后,算子开始对其状态进行异步快照复制。它立即向其输出发出屏障,并继续常规的流处理。一旦后台复制过程完成,它向检查点协调器(JobManager)确认检查点。检查点现在只有在所有的接收点接收到 barrier 并且所有有状态算子都已确认它们的完整备份(可能是在 barrier 到达接收点之后)之后才完成。

3.6、Flink流处理(Stream API)- State & Fault Tolerance(状态和容错)之 State Backends(状态后端)

恢复

这种机制下的恢复非常简单:在发生故障时,Flink 选择最新完成的检查点k,然后系统重新部署整个分布式数据流,并向每个算子提供作为检查点k一部分快照的状态。源被设置为从位置Sk开始读取流。例如在 Apache Kafka 中,这意味着告诉消费者从偏移Sk开始获取。

如果以增量方式快照状态,则操作符从最新的完整快照状态开始,然后对该状态应用一系列增量快照更新。

Flink Managing Execution - Task Failure Recovery(Flink Task 故障恢复)

算子快照实现

在获取算子快照时,有两个部分:synchronous asynchronous

算子和状态后端将它们的快照作为 Java FutureTask 提供。该任务包含同步部分完成和异步部分挂起的状态。异步部分然后由该检查点的后台线程执行。

检查点操作符完全同步地返回一个已经完成的 FutureTask。如果需要执行异步操作,则在 FutureTask 的run()方法中执行。

这些任务是可取消的,因此可以释放流和其他资源消耗句柄。

 

原文地址:https://ci.apache.org/projects/flink/flink-docs-release-1.9/internals/stream_checkpointing.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章