rakulang, dartlang, nimlang, golang, rustlang, lang lang no see

通过状态快照进行容错

焉知非鱼

Fault Tolerance via State Snapshots

状态后端 #

Flink 管理的 keyed state 是一种碎片化的、键/值存储,每项 keyed state 的工作副本都被保存在负责该键的 taskmanager 的本地某处。Operator 的状态也被保存在需要它的机器的本地。Flink 会定期对所有状态进行持久化快照,并将这些快照复制到某个更持久的地方,比如分布式文件系统。

在发生故障的情况下,Flink 可以恢复你的应用程序的完整状态,并恢复处理,就像什么都没有发生过一样。

Flink 管理的这种状态被存储在状态后端中。状态后端有两种实现–一种是基于 RocksDB 的,它是一个嵌入式的键/值存储,将其工作状态保存在磁盘上;另一种是基于堆的状态后端,将其工作状态保存在内存中,在 Java 堆上。这种基于堆的状态后端有两种风味:将其状态快照持久化到分布式文件系统的 FsStateBackend 和使用 JobManager 的堆的 MemoryStateBackend。

名称 工作状态 状态备份 快照
RocksDBStateBackend 本地磁盘(tmp dir) 分布式文件系统 完全/增量
支持大于可用内存的状态; 经验法则:比基于堆的后端慢10倍。
FsStateBackend JVM Heap 分布式文件系统 Full
速度快,需要大量堆积; 受制于 GC
MemoryStateBackend JVM Heap JobManager JVM Heap Full
有利于小状态(地方)的测试和实验。

当处理保存在基于堆的状态后端的状态时,访问和更新涉及到在堆上读写对象。但是对于保存在 RocksDBStateBackend 中的对象,访问和更新涉及到序列化和反序列化,因此成本更高。但是使用 RocksDB 可以拥有的状态数量只受限于本地磁盘的大小。还要注意的是,只有 RocksDBStateBackend 能够进行增量快照,这对于有大量缓慢变化的状态的应用来说是一个很大的好处。

所有这些状态后端都能够进行异步快照,这意味着它们可以在不妨碍正在进行的流处理的情况下进行快照。

状态快照 #

定义 #

  • 快照–一个通用术语,指的是一个 Flink 作业状态的全局、一致的图像。快照包括进入每个数据源的指针(例如,进入文件或 Kafka 分区的偏移),以及来自每个作业的有状态操作符的状态副本,这些操作符是在处理了所有事件后产生的,直到源中的这些位置。
  • 检查点–Flink 为了能够从故障中恢复而自动拍摄的快照。检查点可以是增量的,并为快速恢复进行了优化。
  • 外部化检查点–通常检查点不打算被用户操纵。Flink 只在作业运行时保留n个最近的检查点(n是可配置的),并在作业取消时删除它们。但你也可以配置它们被保留,在这种情况下,你可以手动从它们恢复。
  • 保存点–由用户(或API调用)手动触发的快照,用于某些操作目的,例如有状态的重新部署/升级/重新缩放操作。保存点始终是完整的,并为操作的灵活性进行了优化。

状态快照是如何工作的? #

Flink 使用 Chandy-Lamport 算法的一个变体,称为异步屏障快照。

当任务管理器被检查点协调器(作业管理器的一部分)指示开始检查点时,它让所有的源记录它们的偏移量,并在它们的流中插入编号的检查点障碍。这些屏障在作业图(job graph)中流动,指示每个检查点前后的流的部分。

img

检查点n将包含每个 operator 的状态,这些状态是由于消耗了检查点障碍n之前的每个事件,而没有消耗它之后的任何事件。

当作业图中的每个 operator 接收到这些障碍之一时,它就会记录其状态。具有两个输入流(如 CoProcessFunction)的 operator 执行屏障对齐,这样快照将反映消耗两个输入流的事件所产生的状态,直到(但不超过)两个屏障。

img

Flink 的状态后端使用复制-写机制,允许在异步快照状态的旧版本时,流处理不受阻碍地继续。只有当快照被持久化后,这些旧版本的状态才会被垃圾回收。

一次性保证 #

当流处理应用中出现问题时,有可能出现丢失,或者重复的结果。在 Flink 中,根据你对应用的选择和你运行它的集群,这些结果中的任何一种都是可能的。

  • Flink 不努力从故障中恢复(最多一次)。
  • 没有任何损失,但您可能会遇到重复的结果(至少一次)。
  • 没有任何东西丢失或重复(精确地一次)。

鉴于 Flink 通过倒带和重放源数据流从故障中恢复,当理想情况被描述为精确一次时,这并不意味着每个事件都将被精确处理一次。相反,它意味着每一个事件都会对 Flink 所管理的状态产生一次确切的影响。

Barrier 对齐只需要用于提供精确的一次保证。如果你不需要这个,你可以通过配置 Flink 使用 CheckpointingMode.AT_LEAST_ONCE 来获得一些性能,它的效果是禁用屏障对齐。

精确一次, 端到端 #

为了实现端到端精确的一次,让源的每个事件精确地影响汇,以下几点必须是真的。

  1. 你的源必须是可重播的,并且
  2. 你的接收器必须是事务性的(或幂等的)

实践 #

Flink Operations Playground 包括观察故障和恢复的部分。

进一步阅读 #