有状态流处理

什么是状态? #

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

有状态操作的一些示例:

  • 当应用程序搜索某些事件模式时,状态将存储到目前为止遇到的事件序列。
  • 当聚合每分钟/小时/天的事件时,状态持有待处理的聚合。
  • 在数据点流上训练机器学习模型时,状态保存模型参数的当前版本。
  • 当需要管理历史数据时,状态允许有效访问过去发生的事件。

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

有关状态的知识还允许重新缩放 Flink 应用程序,这意味着 Flink 负责跨并行实例重新分配状态。

可查询状态允许您在运行时从 Flink 外部访问状态。

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

键控状态 #

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

Keyed State 被进一步组织成所谓的Key Groups。Key Groups 是 Fl​​ink 可以重新分配 Keyed State 的原子单元;有与定义的最大并行度一样多的密钥组。在执行期间,键控运算符的每个并行实例都使用一个或多个键组的键。

状态持久化 #

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

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

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

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

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

检查点

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

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

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

障碍 #

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

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

然后障碍物向下游流动。当中间操作符从其所有输入流中接收到快照n的屏障时,它会将快照n的屏障发送到其所有输出流中。一旦接收器操作符(流 DAG 的末尾)从其所有输入流中接收到屏障n,它就会向检查点协调器确认快照n。在所有接收器确认快照后,它被认为已完成。

一旦快照n完成,作业将永远不会再向源询问S n之前的记录,因为那时这些记录(及其后代记录)将通过整个数据流拓扑。

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

  • 一旦操作员从传入的流中接收到快照屏障n,它就无法处理该流中的任何进一步记录,直到它也从其他输入接收到屏障n。否则,它会将属于快照n 的记录与属于快照n+1 的记录混合在一起。
  • 一旦最后一个流接收到屏障n,操作员就会发出所有待处理的传出记录,然后自己发出快照n屏障。
  • 它对状态进行快照并恢复处理来自所有输入流的记录,在处理来自流的记录之前处理来自输入缓冲区的记录。
  • 最后,操作员将状态异步写入状态后端。

请注意,所有具有多个输入的操作符以及在使用多个上游子任务的输出流时经过 shuffle 后的操作符都需要对齐。

快照操作员状态 #

当操作符包含任何形式的state 时,这个 state 也必须是快照的一部分。

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

生成的快照现在包含:

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

恢复 #

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

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

有关详细信息,请参阅重新启动策略

未对齐的检查点 #

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

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

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

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

因此,操作员只是简单地停止处理输入以标记缓冲区,转发屏障,并创建另一个状态的快照。

未对齐的检查点确保障碍尽可能快地到达接收器。它特别适用于具有至少一个缓慢移动数据路径的应用程序,其中对齐时间可能达到数小时。但是,由于它增加了额外的 I/O 压力,因此当状态后端的 I/O 成为瓶颈时,它无济于事。有关 其他限制,请参阅ops 中更深入的讨论 。

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

未对齐的恢复 #

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

状态后端 #

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

保存点 #

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

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

保存点类似于检查点,不同之处在于它们 由用户触发并且不会在新的检查点完成时自动过期

恰好一次 vs. 至少一次 #

对齐步骤可能会给流媒体节目增加延迟。通常,这种额外的延迟大约是几毫秒,但我们已经看到一些异常值的延迟显着增加的情况。对于要求所有记录始终保持超低延迟(几毫秒)的应用程序,Flink 有一个开关可以在检查点期间跳过流对齐。一旦操作员从每个输入中看到检查点屏障,检查点快照仍然会被绘制。

当跳过对齐时,操作员继续处理所有输入,即使在检查点n 的一些检查点障碍到达之后也是如此。这样,运营商也处理属于关卡元素的n + 1的检查点的状态快照之前ñ拍摄。在还原时,这些记录将作为重复出现,因为它们都包含在检查点n的状态快照中,并且将在检查点n之后作为数据的一部分重放。

对齐仅适用于具有多个前导(连接)的运算符以及具有多个发送器的运算符(在流重新分区/洗牌之后)。正因为如此,即使在 至少一次模式下,只有令人尴尬的并行流操作( map()flatMap()filter(), ...)的数据流实际上也只提供 一次保证。

回到顶部

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

Flink 执行批处理程序作为流程序的一个特例,其中流是有界的(有限数量的元素)。甲数据集在内部视为数据流。因此,上述概念以同样的方式适用于批处理程序以及它们适用于流程序,除了少数例外:

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

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

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

回到顶部

编辑这个页面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值