一、flink运行时组件:
1、JobManager(作业管理器)
- 控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的JobManager所控制执行。
- JobManager会先接收到要执行的应用程序,这个应用程序包括:作业图(JobGraph)、逻辑数据流图(logical dataflow graph)、打包了所有的类、库和其他资源的jar包。
- JobManager会把JobGraph转换成一个屋里层面的数据流图,这个图被叫做执行图(ExecutionGraph),包含了所有可以并发执行的任务。
- JobManager会向资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot)。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上,而在运行过程中,JobManager会负责所有需要中央协调的操作,比如检查点(checkpoints)的协调。
2、TaskManager(任务管理器)
- 是Flink中的工作进程。通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量。
- 启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,TaskManager就会将一个或多个插槽提供给JobManager调用,JobManager就可以向插槽分配任务(tasks)来执行了。
- 在执行的过程中,一个TaskManager可以跟其它运行同一应用程序的TaskManager交换数据。
3、ResourceManager(资源管理器)
- 主要负责任务管理器的插槽,TaskManager插槽是flink中定义的处理资源单元。
- flink为不同的环境和资源管理工具提供了不同的资源管理器,比如yarn、mesos、k8s,以及standalone部署。
- 当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager,如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。
4、Dispatcher(分发器)
- 可以跨作业运行,它为应用提交提供了REST接口。
- 当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager。
- Dispatcher也会启动一个webui,用来方便地展示和监控作业执行的信息。
- Dispatcher在架构中可能并不是必须的,这取决于应用提交运行的方式。
二、任务提交流程
上图是从一个较为高层级的视角,来看应用中各组件的交互协作。如果部署的集群环境不同(例如YARN,Mesos,Kubernetes,standalone等),其中一些步骤可以被省略,或是有些组件会运行在同一个JVM进程中。
具体地,如果我们将Flink集群部署到YARN上,那么就会有如下的提交流程:
Flink任务提交后,Client向HDFS上传Flink的Jar包和配置,之后向Yarn ResourceManager提交任务,ResourceManager分配Container资源并通知对应的NodeManager启动ApplicationMaster,ApplicationMaster启动后加载Flink的Jar包和配置构建环境,然后启动JobManager,之后ApplicationMaster向ResourceManager申请资源启动TaskManager,ResourceManager分配Container资源后,由ApplicationMaster通知资源所在节点的NodeManager启动TaskManager,NodeManager加载Flink的Jar包和配置构建环境并启动TaskManager,TaskManager启动后向JobManager发送心跳包,并等待JobManager向其分配任务。
- 并行的任务,需要占用多少个slots?
- 需要先分组,每个组里面最大的task数即为需要slot的数量。
- 一个流处理程序,到底包含多少个任务?
Flink中每个算子后面都可以设置并行度,一般情况下,一个stream的并行度,可以认为就是其所有算子中最大的并行度。
如上图所示,看起来应该是有7个task,实际上某些task可以合并如下。
那么在运行的时候真的需要占用这么多的slot吗?或者必须要有5个slot这个job才能执行起来吗?
默认情况下,Flink允许子任务共享slot,即使他们时不同任务的子任务,这样的结果是一个slot可以保存作业的整个管道。
但是相同操作的不同task任务,是不能共享slot的,不能在一个slot上执行。
如果不想一个slot共享,需要算子后面设置不同的共享组。setSharingGroup(""),默认是使用共享组并且共享组名为default。
Flink中依据什么来划分task是否能合并?
必须是共享组、并行度相同、并且是one-to-one的操作
如果不想合并,代码层面设置disableOperatorChaining或startnewchain
数据的传输形式:
算子之间传输数据的形式可以是one-to-one(forwarding)的模式,也可以是redistributing的模式,具体是哪一种形式,取决于算子的种类。
one-to-one:stream维护这分区以及元素的顺序,这意味着map算子的子任务看到的元素的个数以及顺序跟source算子的子任务生产的元素的个数、顺序相同。map、filter、flatmap等算子都是one-to-one的对应关系。(类似于spark中的窄依赖)
redistributing:stream的分区会发生改变,每一个算子的子任务依据所选择的transformation发送数据到不容的目标任务。例如keyby基于hashcode重分区、而broadcast和rebalance(轮询,而shuffle是完全随机的)会随机重新分区,这些算子都会引起redistribute过程,而redistribute过程就类似于spark中的shuffle过程。(类似于spark中的宽依赖)