一、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在架构中可能并不是必须的,这取决于应用提交运行的方式。
Flink客户端:
用来提交Flink作业到Flink集群中,在客户端中负责Stream Graph(流图)和Job Graph(逻辑作业图)的构建(使用Table Api和SQL编写的Flink应用还会在客户端中负责SQL解析和优化)。
Dispatcher:
Dispatcher可以接收多个作业,每接收一个作业,Dispatcher都会为这个作业分配一个JobManager。
Dispatcher对外提供一个表述性状态转移(REST)式的接口,以超文本传输协议来对外提供服务
JobManager:
一个Flink作业的协调者,一个作业会有一个JobManager来负责。
JobManager将Client提交的JobGraph转化为ExecutionGraph(物理执行图)
向ResourceManager申请必要的资源,当获取到足够的资源后
JobManager将ExecutionGraph以及具体的计算任务分发部署到多个TaskManager上
同时JobManager还负责管理多个TaskManager,包括收集作业的状态信息、生成检查点、必要时进行故障恢复等。
TaskManager:
是实际负责执行的计算节点。
单个TaskManager提供一定量的slot,TaskManager启动后相关的slot信息会被注册到ResourceManager中。
当某个作业提交后,ResourceManager会将空闲的slot提供给JobManager,获取到空闲的slot后会将具体的计算任务部署到空闲slot上开始执行,执行过程中,由于进行数据交换,TaskManager之间进行必要的数据通信。
ResourceManager:
Flink使用一个名为ResourceManager的模块来统一处理资源分配上的问题。
flink中计算资源基本单位是TaskManager上的任务槽slot,ResourceManager的职责主要是从Yarn等资源提供方获取计算资源,当JobManager有计算需求时,将空闲的slot分配给JobManager,当计算结束时,ResourceManager还会重新收回这些slot。
二、任务提交流程
上图是从一个较为高层级的视角,来看应用中各组件的交互协作。如果部署的集群环境不同(例如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
执行图:
Flink中的执行图可以分为四层:StreamGraph -> JobGraph -> ExecutionGraph ->物理执行图
StreamGraph:是根据用户通过Stream API编写的代码生成的最初的图,用来表示程序的拓扑结构。
JobGraph:StreamGraph经过优化后生成了JobGraph,提交给Jobmanager的数据结构。主要的优化为,将多个符合条件的节点chain在一起作为一个节点。
ExecutionGraph:Jobmanager根据JobGraph生成ExecutionGraph。ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。
物理执行图:JobManager根据ExecutionGraph对Job进行调度后,在各个TaskManager上部署Task后形成的图,并不是一个具体的数据结构。
数据的传输形式:
算子之间传输数据的形式可以是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中的宽依赖)