- 所有的Flink由三部分组成 Source、Transformation、Sink
Source负责读取数据源 Transformation利用各种算子进行处理加工 Sink负责输出 在运行时 Flink上运行的程序会被映射成 "逻辑数据流" dataflows 它包含了这三部分 每一个dataflow以一个或多个sources开始 以一个或多个sinks结束
- dataflow类似于任意的有向无环图(DAG)
在大部分情况下 程序的转换算法(transformations)跟dataflow中的算子(operator)是一一对应关系 但有时候一个transformations可能对应多个operator
执行图(ExecutionGraph)
由Flink程序直接映射成数据流图 StreamGraph 也被成为逻辑流图 因为它们表示的是计算逻辑的高级视图 为了执行一个流处理程序 Flink需要将逻辑流图转换为物理数据流图(也叫执行图)详细说明程序的执行方式
- Flink执行图可以分为四层
StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图
- StreamGraph
是根据用户通过Stream API编写的代码生成的最初的图 用来表示程序的拓扑结构
- JobGraph
StreamGraph经过优化后生成了JobGraph 提交给JobManager的数据结构 主要优化为: 将多个符合条件的节点 chain在一起作为一个节点 这样可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗
- ExecutionGraph
JobManager根据JobGraph生成了ExecutionGraph ExecutionGraph是JobGraph的并行化版本 是调度层最核心的数据结构
- 物理执行图
JobManager根据ExecutionGraph对Job进行调度后 在各个TaskManager上部署Task后形成的“图” 并不是一个具体的数据结构
并行度(Parallelism)
Flink程序的执行具有并行、分布式特性 一个流包含了一个或多个分区(stream partition) 而每一个算子(operator)可以包含一个或多个子任务(operator subtask) 这些子任务在不同的线程、不同物理机或不同的容器中不依赖的执行
- 并行数据流
一个特定算子的子任务(subtask)的个数被称为并行度 一般情况下 一个流程序的并行度 可以认为其所有算子中最大的并行度
一个程序中 不同的算子可能具有不同的并行度 Stream在算子之间传输数据的形式可以是 one-to-one(forwarding)的模式也可以是redistributing的模式 具体是哪一种形式 取决于算子的种类 one-to-one: stream(比如在source和map operator之间) 维护着分区以及元素的顺序 那意味着map算子的子任务看到的元素的个数以及顺序跟source算子的子任务生产的元素的个数、顺序相同 map、filter、flatMap等算子都是one-to-one的对应关系 Redistributing: stream(map()跟keyBy/window之间或者keyBy/window跟slink之间)的分区会发生改变 每一个算子的子任务依据所选择的transformation发送数据到不同的目标任务 例如: keyBy()基于hashCode重分区 broadcast和rebalance会随机重新分区 这些算子都会引起redistribute过程 该过程就类似于spark中的shuffle 类似于spark的窄依赖、宽依赖