flink有状态流处理

原创
2022/02/13 15:38
阅读数 208

What is State? #

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

一些有状态操作的例子:

  • 当应用程序搜索特定的事件模式时,状态将存储到目前为止遇到的事件序列。
  • 当以分钟/小时/天的速度聚合事件时,该状态保存未决的聚合。
  • 当在一串数据点上训练一个机器学习模型时,状态保存模型参数的当前版本。
  • 当需要管理历史数据时,状态允许对过去发生的事件进行有效访问。

Flink需要知道状态,以便使用检查点和保存点使其容错。

了解状态还可以缩放Flink应用程序,这意味着Flink负责跨并行实例重新分配状态

Queryable state允许您在运行时从Flink外部访问状态。

在使用状态时,阅读关于Flink的状态后端可能也很有用。Flink提供了不同的状态后端,用于指定状态的存储方式和存储位置。

Keyed State #

键状态被维护在一个嵌入式键/值存储中。状态与有状态操作符读取的流一起被严格划分和分发。因此,对键/值状态的访问只可能在键流上,即在键/分区数据交换之后,并且被限制为与当前事件的键相关联的值。对齐流和状态的键可以确保所有的状态更新都是本地操作,保证了一致性而没有事务开销。这种对齐还允许Flink重新分配状态并透明地调整流分区

State and Partitioning

键状态被进一步组织成所谓的键组。键组是Flink可以重新分发键状态的原子单位;键组的数量与定义的最大并行度相同。在执行期间,键控操作符的每个并行实例都使用一个或多个键组的键。

状态持久化

Flink使用流重放和检查点的组合来实现容错。检查点标记每个输入流中的特定点,以及每个操作符的对应状态。通过恢复操作符的状态并从检查点重放记录,流数据流可以从检查点恢复,同时保持一致性(仅一次处理语义)。

检查点间隔是一种将执行期间的容错开销与恢复时间(需要重放的记录的数量)进行权衡的方法。

容错机制连续绘制分布式流数据流的快照。对于状态较小的流应用程序,这些快照非常轻量级,可以频繁地绘制,而不会对性能造成太大影响。流应用程序的状态存储在可配置的位置,通常在分布式文件系统中。

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

缺省情况下,检查点是禁用的。有关如何启用和配置检查点的详细信息,请参见检查点。
为了让这个机制实现它的全部保证,数据流源(如消息队列或代理)需要能够将流倒回到最近定义的点。Apache Kafka有这个能力,而Flink到Kafka的连接器利用了这个能力。有关Flink连接器提供的保证的更多信息,请参阅数据源和接收器的容错保证。
因为Flink的检查点是通过分布式快照实现的,所以我们可以交替使用快照和检查点这两个词。我们也经常使用术语快照来表示检查点或保存点。

Checkpointing #

Flink容错机制的核心部分是绘制分布式数据流和操作员状态的一致性快照。这些快照充当一致的检查点,系统在出现故障时可以返回到这些检查点。Flink绘制这些快照的机制在“分布式数据流的轻量级异步快照”中有描述。它受到分布式快照标准Chandy-Lamport算法的启发,并专门为Flink的执行模型量身定制。

请记住,所有与检查点相关的操作都可以异步完成。检查点障碍不会在锁步中移动,操作可以异步快照它们的状态。

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

Barriers #

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

Checkpoint barriers in data streams

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

然后这些屏障就会顺流而下。当一个中间操作符从它所有的输入流接收到一个snapshot n的barrier时,它会向所有的输出流发出一个snapshot n的barrier。一旦接收操作符(流DAG的末端)从它所有的输入流接收到barrier n,它就向检查点协调器承认快照n。在所有接收器都确认了快照之后,就认为快照完成了。

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

Aligning data streams at operators with multiple inputs

 

Snapshotting Operator State #

当操作符包含任何形式的状态时,该状态也必须是快照的一部分。

操作符在从输入流接收到所有快照屏障时,以及在向输出流发送屏障之前,对它们的状态进行快照。在这一点上,所有对状态的更新都来自屏障之前的记录,并且没有依赖于屏障应用之后的记录的更新。因为快照的状态可能很大,所以它存储在可配置的状态后端。默认情况下,这是JobManager的内存,但是对于生产使用,应该配置一个分布式的可靠存储(例如HDFS)。存储状态之后,操作员确认检查点,向输出流发出快照屏障,然后继续。

生成的快照现在包含:

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

Recovery #

这一机制下的恢复很简单:当一个失败时,Flink选择最近完成的检查点k。然后系统重新部署整个分布式数据流,并给每个操作人员作为检查点k的一部分被快照的状态。源被设置为从位置Sk开始读取流。这意味着告诉消费者开始从偏移Sk取

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

有关更多信息,请参见重启策略。

Unaligned Checkpointing #

检查点也可以不对齐地执行。其基本思想是,只要飞行中的数据成为Operator状态的一部分,检查点就可以覆盖所有飞行中的数据。

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

Unaligned checkpointing

下图描述了操作员如何处理未对齐的检查点障碍:

operator对存储在输入缓冲区中的第一个barrier作出反应。
它通过将barrier添加到输出缓冲区的末尾,立即将barrier转发给下游操作符。
该操作符将所有被超过的记录标记为异步存储,并创建自己状态的快照。
因此,operator只是短暂地停止对输入的处理,以标记缓冲区,转发屏障,并创建其他状态的快照。

未对齐的检查点确保障碍物尽可能快地到达水槽。它特别适合至少有一个缓慢移动的数据路径的应用程序,其中校准时间可以达到几个小时。然而,由于它增加了额外的I/O压力,当状态后端的I/O成为瓶颈时,它并没有帮助。有关其他限制,请参阅ops中的更深入的讨论。

注意保存点总是对齐的。

Unaligned Recovery #

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

State Backends #

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

checkpoints and snapshots

Savepoints #

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

保存点是手动触发的检查点,它获取程序的快照,并将其写入状态后端。他们依赖于常规的检查点机制。

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

Exactly Once vs. At Least Once #

对齐步骤可能会增加流程序的延迟。通常,这种额外的延迟是几毫秒的量级,但我们看到过一些异常值的延迟显著增加的情况。对于所有记录都需要持续超低延迟(几毫秒)的应用程序,Flink有一个开关,可以在检查点期间跳过流对齐。当operator从每个输入中看到检查点屏障时,检查点快照仍然被绘制。

当跳过Alignment时,操作符继续处理所有输入,即使到达了检查点n的某些checkpoint barrier。这样,操作符还在获取检查点n的状态快照之前处理属于检查点n+1的元素。在恢复时,这些记录将作为副本出现,因为它们都包含在检查点n的状态快照中,并且将在检查点n之后作为数据的一部分重新播放。

对齐只会发生在 具有多个前身的操作符(连接)以及 具有多个发送者的操作符(在流重新分区/shuffle之后)。因此,只有令人尴尬的 并行流操作(,,,…)的数据流实际上只提供一次保证,即使在At Least Once模式下。 map()flatMap() filter()

State and Fault Tolerance in Batch Programs #

Flink作为流程序的一种特殊情况执行批处理程序,其中流是有边界的(有限数量的元素)。数据集在内部被视为数据流。因此,上面的概念同样适用于批处理程序和流处理程序,但有一些小例外:

  • 批处理程序的容错不使用检查点。恢复是通过完全重放流来实现的。这是可能的,因为输入是有界的。这将更多的成本推向恢复,但使常规处理更便宜,因为它避免了checkpoint。

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

DataSet API引入了特殊的同步(基于超步的)迭代,这只可能在有界流上实现。有关详细信息,请查看迭代文档。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部