键控状态(Keyed State)被维护在可以被认为是嵌入式键/值存储中。 状态(state)与有状态算子(the stateful operators)读取的流一起严格分区和分布。 因此,对键/值状态的访问只能在键控流(Keyed Stream)上进行,即在键控/分区数据交换之后,并且仅限于与当前事件的键关联的值。对齐 流和状态的键(keys of stream and state)可确保所有状态更新都是本地操作,从而保证一致性而无需事务开销。 这种对齐还允许 Flink 重新分配状态并透明地调整流分区。
键控状态(Keyed State)进一步组织成所谓的键组(Key Groups)。 Key Groups 是 Flink 可以重新分配 Keyed State 的原子单元; 键组(Key Groups)的数量与定义的最大并行度完全相同。在执行期间,键控(Keyed)算子的每个并行实例都使用一个或多个键组的键。
State Persistence
stream barrier被注入到流源处的并行数据流中。 快照 n 的barrier被注入的点(我们称之为 Sn)是源流中快照覆盖数据的位置。 例如,在 Apache Kafka 中,该位置将是分区中最后一条记录的偏移量。 这个位置 Sn 被报告给检查点(checkpoint)协调器(Flink 的 JobManager)。
然后barrier流向下游。 当中间Operators(算子)从其所有输入流接收到快照 n 的屏障时,它将向其所有输出流发出快照 n 的barrier。 一旦sink Operator(Stream DAG 的末端)从其所有输入流接收到barrier n,它就会向检查点(checkpoint)协调器确认该快照 n. 当所有接收器都确认快照后,该快照就被认为已完成。
一旦快照 n 完成,作业将不再向源请求 Sn 之前的record,因为此时这些record(及其后的record)将已经穿过整个数据流拓扑。
所有使用checkpoint的程序都可以从savepoint恢复执行。savepoint允许更新您的程序和 Flink 集群,而不会丢失任何状态。
savepoint是手动触发的checkpoint,它进行程序snapshot并将其写入状态后端。 为此,他们依赖定期checkpoint机制。
savepoint与checkpoint类似,不同之处在于它是由用户触发的,并且在新的checkpoint完成时不会自动过期。
Exactly Once vs. At Least Once
对齐步骤可能会增加stream程序的延迟。 通常,这种额外的延迟约为几毫秒,但我们已经看到一些异常值的延迟明显增加的情况。 对于所有记录都需要一致超低延迟(几毫秒)的应用程序,Flink 有一个开关可以在checkpoint期间跳过 流对齐。 一旦算子 看到来自每个输入的checkpoint barrier,仍然会绘制checkpoint快照。
当跳过对齐时,算子会继续处理所有输入,即使在checkpoint n 的一些checkpoint barrier到达之后也是如此。 这样,在获取checkpoint n 的状态快照之前,算子还会处理属于checkpoint n+1 的元素。在恢复时,这些record将作为重复项出现,因为它们都包含在checkpoint n 的状态快照中,并且将在checkpoint n 之后作为数据的一部分重放。