Flink 通过 barrier 来协调 checkpoint 的时机,我们在介绍【Flink 网络栈】的时候已经有介绍:对于一个拓扑结构,只有上游算子 checkpoint 完成,下游算子的 checkpoint 才能开始并有意义,又因为下游算子的消费速率并不统一【有的 channel 快,有的 channel 慢】,barrier 就是这样一种协调上下游算子的机制。
Flink 分布式快照的设计-存储
分布式快照是整个 Flink 计算框架中非常核心的模块,Flink 的 checkpoint、状态存储都依赖于其分布式快照;不仅框架自身借助于 chandy-lamda 算法,实现了算子状态的快照和恢复,也对用户暴露了一套简洁的状态存储的 API,用户无需关心快照自身的容错/扩展/一致性,这些 Flink 都已对用户透明;由于分布式快照这块的设计比较复杂,因此将拆成两篇文章来介绍,本篇文章主要介绍分布式快照存储部分的设计,下一篇会介绍快照的流程和细节。
代码参考版本: 1.5-SNAPSHOT。
核心模块
Flink 的分布式快照存储部分设计抽象出了大致 5 个层次:
- 最底层是快照的物理存储,包括内存和文件系统两种形式
- 再上层是 CheckpointStreamFactory:封装了具体的存储交互,也就是内存/文件系统读写
- 再上层是 StateBackend:封装了工作状态的存储逻辑,包括内存和 RocksDB 两种形式
- 再上层是 KeyedStateBackend:封装了快照的读写细节,快照分区策略等
- 再上层是 State:封装了与 KeyedStateBackend 交互时状态的 val 序列化/反序列化 等逻辑
还有一个 StateContext 比较特殊,它不提供快照功能,只提供临时的状态读写,下面会讲到
核心模块的总体交互图:
Flink WindowOperator 的设计
Flink Kafka Connector 设计与实现
Flink 对用户代码异常处理
Flink Scheduler
前面已经介绍了一系列的 flink 任务抽象、网络传输、可靠性机制等细节,有了这些铺垫,终于可以开心的介绍 flink 的任务调度机制了
因为没有这些铺垫,就无法明白 flink 为什么要设计这样的一套调度机制!所以本章节讲解时会多穿插一些为什么
资源组
资源组模型
flink 的一个 Instance 可以被划分出多个 Slot,通过初始参数可以指定,他们既可以是 SimpleSlot,也可以是同时跑多个 task 的 SharedSlot,为了约束 task 之间的运行时的绑定关系,flink 抽象出了 SlotSharingGroup 和 CoLocationGroup 的概念。
一个 SlotSharingGroup 规定了一个 Job 的 DAG 图中的哪些 JobVertex 的 sub task 可以部署到一个 SharedSlot 上,这是一个软限制,并不是一定会满足,只是调度的时候有位置偏好,而 CoLocationGroup 是在 SlotSharingGroup 的基础上的硬限制,它限定了 CoLocationGroup 中的 JobVertex 中的 sub task 运行必须是一一对应的:假如 CoLocationGrou 限定了 JobVertex A 和 B ,那么 A 的编号为 i 的 sub task 必须和 B 的编号为 i 的 sub task 跑在一起。假如一个 job 的运算逻辑包括 source -> head -> tail -> sink,那么它的 task 运行时限制关系见下图: