Flink Concept Stateful Stream Processing -Flink概念有状态流处理


【翻译来源Flink官方】

有状态流处理

什么是状态

虽然数据流中的许多操作符一次仅查看一个事件(例如一个事件解析器),但某些操作符会记住多个事件的信息(例如窗口操作符)。这些操作符称为有状态的操作符。

状态是数据结构,存储与状态后端。
通过记忆的方式来实现容错功能,具体包括检查点和保存点。还支持Flink应用程序的状态重分配。
状态提供外部访问接口。

keyed 状态

带key的状态是内部状态,是key/value样式的流,keyed状态只能流上可以访问。

相比于普通状态带keyed的状态应该不可以外部访问和外部存储。

对齐流上key们和状态确保了所有状态更新是本地操作,保证了一致性而没有事务开销。
这种对齐操作是透明的,用户不可见的,允许Flink重新分配状态透明的调整流分区。

keyed状态的组织结构是Key Groups,Key Groups是Flink重新分配keyed状态的原子单位。Key Groups的个数跟定义的最大并行度一样多。
一个keyed运算符使用一个或多个Key Groups的健。

状态持久性

Flink通过结合流重播和 检查点来实现容错。

在执行期间,检查点间隔是权衡容错开销恢复时间(需要重播的记录数决定了恢复时间)的一种方法。

对于状态较小的流应用程序,这些快照非常轻巧,可以在不影响性能的情况下频繁绘制。

流应用程序的状态通常存储在分布式文件系统中的可配置位置。

如果发生程序故障(由于机器,网络或软件故障),Flink将停止分布式流数据流。然后,系统重新启动操作员,并将其重置为最新的成功检查点。

注意:
默认情况下,检查点是禁用的。
数据流源(例如消息队列或代理)必须能够将流后退到定义的最近点。Apache Kafka具有此功能。
由于Flink的检查点是通过分布式快照实现的,因此我们可以交替使用快照和检查点一词。通常,我们也使用快照一词来表示检查点或保存点。

checkpoint

检查点。
Flink容错机制的核心是绘制分布式数据流和操作符状态的一致快照。

这些快照充当一致的检查点,如果发生故障,系统可以回退到这些检查点。

与检查点有关的所有操作都可以异步完成。

检查点barriers不会在锁定步骤中传播,并且操作符们可以异步快照它们的状态。

从Flink 1.11开始,检查点可以对齐或不对齐。在本节中,我们首先描述对齐的检查点。

Barriers

流barriers是Flink分布式快照中的核心元素。这些barriers将注入到数据流中,并与记录一起作为数据流的一部分流动。barriers从不超越记录,它们严格按照顺序进行。

barriers将数据流中的记录分为进入当前快照的记录集和进入下一个快照的记录集。

每个barriers都携带快照的ID,快照的记录已被推送到快照的前面。

屏障不会中断流的流动,因此非常轻量。

来自不同快照的多个barriers可以同时出现在流中,不同快照可能同一时刻发生。


上图中,一个barrier把checkpoint代表的快照分开。

流barriers在流源头处注入到并行数据流中。快照n的barriers被注入的点(我们称其为 S n)取决于在源流中快照覆盖数据的位置。例如,在Apache Kafka中,此位置将是分区中最后一条记录的偏移量。该位置S n 被报告给检查点协调器(Flink的JobManager)。

然后,barriers向下游移动。当中间的操作符从其所有输入流中收到一个快照n的barrier时,它会将快照n的barrier发射到其所有输出流中。一旦sink运算符(流式DAG的末尾)从其所有输入流接收到barrier n后,便将快照n确认给检查点协调器。所有sink运算符都确认快照后,就认为快照已完成。

一旦完成快照n,该作业job将不再向源source请求S n之前的记录,因为此时这些记录(及其后代记录)将通过了整个数据流拓扑图。


接收到多个输入流的操作符需要在快照barriers上对齐输入流。上图说明了这一点:

  • 操作符一旦从传入流中接收到快照barrier n,就无法处理该流中的任何更远的记录,直到操作符也已经从其他输入流接收到屏障n为止。否则,操作符会混淆属于快照n的记录和属于快照n + 1的记录。
  • 一旦操作符接收了最后一个流接收到的barrier n,操作符将发出所有待发的记录,然后它自身发出快照 n barrier。
  • 操作符快照状态并从所有输入流中恢复处理中的记录,处理来自流中的记录之前,先处理输入缓冲区input buffers中的记录。
  • 最后,操作符将状态异步写入状态后端。

请注意,具有多个输入流的所有运算符和消费多个上游子任务的输出流的操作符shuffle后时,都需要对齐。

快照操作符状态

当操作符包含任何形式的状态时,该状态也必须是快照的一部分。
操作符在输入流接收到所有快照barriers的时间点,向输出流发出barriers之前,对其状态进行快照。届时,将在barriers之前产生所有来自记录对状态的更新,而依赖于来自己barriers之后的记录没有更新被应用。由于快照的状态可能很大,因此将其存储在可配置状态backend中。默认情况下,这是JobManager的内存,但对于生产用途,应配置分布式可靠存储(例如HDFS)。存储状态后,操作符确认检查点,将快照屏障发送到输出流中,然后继续。

现在生成的快照包含以下部分:

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

恢复

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

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

未对齐检查点

从Flink 1.11开始,检查点也可以不对齐地执行。基本思想是,只要in-flight的数据成为操作符状态的一部分,检查点就可以覆盖所有in-flight的数据。

请注意,这种方法实际上更接近Chandy-Lamport算法 ,但是Flink仍将barrier插入源中,以避免使检查点协调器过载。

该图描述了操作符如何处理未对齐的检查点barrier:

  • 操作符对存储在其输入缓冲区input buffers中的第一个barrier做出反应。
  • 通过将barrier添加到输出缓冲区的末尾,它将立即将屏障转发给下游操作符。
  • 操作符将所有超越的记录标记为异步存储,并创建其自身状态的快照。

因此,操作符仅短暂停止输入的处理以标记缓冲区,转发barrier并创建其他状态的快照。

未对齐的检查点可确保barriers尽快到达sink。它特别适合于具有至少一条缓慢移动的数据路径的应用,其中对齐时间可能长达数小时。但是,由于它增加了额外的I / O压力,因此当状态后端的I / O成为瓶颈时,这无济于事。看到更深入的讨论 ops 的其他限制。

请注意,保存点将始终对齐。

未对齐的恢复

在开始处理来自上游操作符的未对齐检查点中的任何数据之前,操作符首先要恢复in-flight的数据。除此之外,它执行与恢复对齐检查点期间相同的步骤。

状态后端

存储键/值索引的确切数据结构取决于所选的状态后端。一个状态后端将数据存储在内存中的哈希表中,而另一个状态后端使用RocksDB作为键/值存储。除了定义保存状态的数据结构外,状态后端还实现逻辑以获取键/值状态的时间点快照并将该快照存储为检查点的一部分。可以无需更改应用程序逻辑配置状态后端。

保存点

所有使用检查点的程序都可以从保存点恢复执行。保存点可以在不丢失任何状态的情况下更新程序和Flink群集。

保存点们是 手动触发的检查点们,它们为程序创建快照并将其写到状态后端。为此他们依靠常规的检查点机制。

保存点与检查点类似,除了它们 由用户触发并且在完成新的检查点时不会自动过期。

确保一次与至少一次

对齐步骤可能会增加流程序延迟。通常,这种额外的延迟大约为几毫秒,但是我们看到一些异常值的延迟显着增加的情况。对于要求所有记录始终具有超低延迟(几毫秒)的应用程序,Flink可以在在检查点期间切换到跳过流对齐。一旦操作符从每个输入看到检查点barrier,仍然会绘制检查点快照。

跳过对齐后,即使在检查点n的某些检查点barriers到达之后,操作符仍会继续处理所有输入。这样,操作符还可以在获取检查点n的状态快照之前处理属于检查点n + 1的元素。在还原时,这些记录将作为重复记录出现,因为它们都包含在检查点n的状态快照中,并将作为检查点n之后的数据的一部分进行重放。

注意:对齐仅对具有多个前任(joins)的操作符以及具有多个发送方的运算符(在流repartitioning/shuffle)进行。正因为如此,仅有尴尬的并行的流操作符的数据流(map(),flatMap(),filter(),...)甚至在至少一次的模式中给出实际一次的保证。

批处理程序中的状态和容错

Flink执行批处理程序,这是流程序的特例,其中流是有界的(元素数量有限)。一个数据集在内部视为数据流。因此,以上概念以相同的方式适用于批处理程序,也适用于流式传输程序,只有少数例外:

  • 批处理程序的容错 功能不使用检查点。通过完全重播流来进行恢复。这是可能的,因为输入是有界的。这将成本更多地推向了恢复,但由于避免了检查点,因此使常规处理的成本降低了。

  • DataSet API中的状态操作使用简化的内存/核外数据结构,而不是键/值索引。

  • DataSet API引入了特殊的同步(superstep-based)迭代,仅在有限流上才有可能。有关详细信息,请查看迭代文档

原文地址:https://www.cnblogs.com/qlxm/p/14441898.html