Flink 运行时组件

目录

一、四大组件

二、任务提交流程

三、任务提交到 YARN上的执行流程

四、任务调度原理

五、TaskManager 和 Slots

六、任务链

七、程序与数据流

八、数据流和执行图

九、并行子任务的分配

十、数据传输的形式


一、四大组件


JobManager(分配任务,调度checkpoint做快照)、TaskManager(主要干活的)、ResourceManager(资源管理器,分配资源,管理资源)、Dispacher(方便提交任务的接口,WebUI)
Flink 运行时组件_第1张图片
JobManger 作业管理器:
【1】控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的 JobManager所控制执行;
【2】JobManager 会先接收到要执行的应用程序,这个应用程序会包括:作业图(JobGraph 根据程序代码的每一步操作都对应一个任务,基于这些任务就可以整合成一张图,这个图就是 JobGraph)、逻辑数据流图(Logical dataflow graph)和打包了所有的类、库和其他资源的 Jar包(程序代码);
【3】JobManager会把 JobGraph转换成一个物理层面的数据流图(拥有并行度),这个图被叫做“执行图”(ExecutionGraph),包含了所有可以并发执行的任务。
【4】JobManager会向资源管理器(ResourceManger)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot)。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的 TaskManager上。而在运行过程中,JobManager会负责所有需要中央协调的操作,比如检查点(checkpoints)的协调。

TaskManager 任务管理器:
【1】Flink 中的工作进程。通常在Flink中会有多个 TaskManager运行,每一个 TaskManager都包含了一定数量的插槽(sots)。插槽的数量限制了TaskManager 能够执行的任务数量;
【2】启动之后 TaskManager会向资源管理器注册它的插槽,收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给 JobManager调用。 JobManage就可以向插槽分配任务( tasks)来执行了;
【3】在执行过程中,一个 TaskManager可以跟其它运行同一应用程序的 TaskManager交换数据;

ResourceManager 资源管理器
【1】主要负责管理任务管理器( TaskManager) 的插槽(slot),TaskManager插槽是 Fink中定义的处理资源单元;
【2】Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARNMesos、K8s 以及 standalone部署;
【3】当 JobManager申请插槽資源时,ResourceManager会将有空闲插槽的TaskManager分配给 JobManager。如果ResourceManager没有足够的插槽来满足 JobManager的请求,它还可以向资源提供平台发起会话,以提供启动 TaskManager进程的容器。

Dispacher 分发器
【1】可以跨作业运行,它为应用提交 提供了 REST接口;
【2】当一个应用被提交执行时,分发器就会启动并将应用移交给一个 JobManager;
【3】Dispatcher也会启动一个WebUI,用来方便地展示和监控作业执行的信息;
【4】Dispatcher在架构中可能并不是必需的,这取决于应用提交运行的方式;

二、任务提交流程


Flink 运行时组件_第2张图片

三、任务提交到 YARN上的执行流程


其中ApplicationMaster 启动JobManager 的时候会连带 Flink的 ResourceManager 一块启动。JobManager 会向 Flink 的ResourceManager 申请资源,而 Flink 的RM会向 YARN 的RM申请资源。Flink 运行时组件_第3张图片

四、任务调度原理


运行时状态,Flink Program 生成一个数据流图,经过Client客户端处理之后将其提交给 JobManager,在JobManager 中根据并行度生成一个执行图。就会申请足够的 Task Slot ,最后将任务分配到 TaskSlot中。
Flink 运行时组件_第4张图片
Flink系统架构设计如上图所示,可以看出 Flink整个系统主要由两个组件组成,分别为 JobManager TaskManager,Flink架构也遵循 Master-Slave架构设计原则,JobManager为Master节点,TaskManager为Worker(Slave)节点。所有组件之间的通信都是借助于Akka Framework,包括任务的状态以及 Checkpoint触发等信息。
【1】Client客户端:客户端负责将任务提交到集群,与 JobManager构建 Akka连接,然后将任务提交到 JobManager,通过和JobManager之间进行交互获取任务执行状态。客户端提交任务可以采用 命令行接口 CLI方式或者通过使用 Flink WebUI提交,也可以在应用程序中指定 JobManager的 RPC网络端口构建 ExecutionEnvironment提交 Flink应用。
【2】JobManager:JobManager负责整个 Flink集群任务的调度以及资源的管理,从客户端中获取提交的应用,然后根据集群中TaskManager上 TaskSlot的使用情况,为提交的应用分配相应的 TaskSlots资源并命令 TaskManger启动从客户端中获取的应用。JobManager相当于整个集群的Master节点,且整个集群中有且仅有一个活跃的JobManager,负责整个集群的任务管理和资源管理。JobManager和TaskManager之间通过Actor System进行通信,获取任务执行的情况并通过Actor System将应用的任务执行情况发送给客户端。同时在任务执行过程中,Flink JobManager会触发Checkpoints操作,每个TaskManager节点收到Checkpoint触发指令后,完成Checkpoint操作,所有的Checkpoint协调过程都是在Flink JobManager中完成。当任务完成后,Flink会将任务执行的信息反馈给客户端,并且释放掉TaskManager中的资源以供下一次提交任务使用。
【3】TaskManager:TaskManager相当于整个集群的Slave节点,负责具体的任务执行和对应任务在每个节点上的资源申请与管理。客户端通过将编写好的Flink应用编译打包,提交到JobManager,然后JobManager会根据已经注册在JobManager中TaskManager的资源情况,将任务分配给有资源的TaskManager节点,然后启动并运行任务。TaskManager从JobManager接收需要部署的任务,然后使用Slot资源启动Task,建立数据接入的网络连接,接收数据并开始数据处理。同时TaskManager之间的数据交互都是通过数据流的方式进行的。
可以看出,Flink的任务运行其实是采用多线程的方式,这和MapReduce多JVM进程的方式有很大的区别Fink能够极大提高CPU使用效率,在多个任务和Task之间通过TaskSlot方式共享系统资源,每个TaskManager中通过管理多个TaskSlot资源池进行对资源进行有效管理。设置的slot的数量指的是每个 TaskManager上的slot个数,并不是指全部。

五、TaskManager 和 Slots


Fink中每一个 TaskManager 都是一个 MM进程,它可能会在独立的线程上执行一个或多个 subtask。为了控制一个 TaskManager能接收多少个task,TaskManager通过 task slot来进行控制(一个 TaskManager至少有一个slot)。我们把 TM看做进程的话,slot 就相当于其上的线程。每个线程执行在固定的计算资源上,这个资源就是slot,slot 之间内存是独享的。如果一个线程挂了,其它是不受影响的。CPU 不是独享的。为了充分利用资源,我们一般讲slot的数量设置成cpu核心线程数的大小,这样CPU资源就不用进行切换,可以提高性能。下面是5个任务,最大并行度是2。并不是分配5个slot,我们可以将 slot进行共享。

Flink 运行时组件_第5张图片

我们将上图前两个任务并行度提高到6,总共是13个任务:默认情况下,Fink允许子任务共享slot,可以提高资源的利用率。即使它们是不同任务的子任务。这样的结果是,一个 slot可以保存作业的整个管道。Task slot是静态的概念,是指 TaskManager具有的并发执行能力。为了减少数据在机器之间传输带来的序列化和网络传输问题,就出现了下面的两个任务合并为一个任务的情况,不同的任务出现在一个slot上,调用就像调用本地任务一样。

并行的概念:① 数据并行指同一个任务,不同的并行子任务,同时处理不同的数据。② 任务并行指同一时间不同 slot在执行不同的任务。

Flink 运行时组件_第6张图片
下面有3个核心数,我们就按照推荐的分配三个 slot,程序例如也就 WordCound的三步操作。

上面的图,我们可以看出来,对Slot还是没有充分利用,那么多少才是真正的充分利用,当并行度为9的时候,就会充分利用。如下,总共27个任务,分配在9个Slot中。默认Flink会将我们的算子都加载到一个 slot上(默认为 default 组),那如果我们就想一个slot上面只定义特定的算子,该如何处理?其实很简单,给算子加上组。如下, ONCE 表示组,用户可以将共享 slot的算子设定为相同的组。

filter(_.nonEmpty).slotSharingGroup("ONCE")

Flink 运行时组件_第7张图片
还要就是程序的最后是输出到文件中,上图就会输出到不同的文件中,因此下面就是讲最后一个任务只分配到一个Slot中,这样保证输出的结果只保存在一个文件中。
Flink 运行时组件_第8张图片

一个流处理程序需要的 slot 数量,其实就是所有任务中最大的那个并行度。

六、任务链


Flink采用了一种称为任务链的优化技术,可以在特定条件下减少本地通信的开销。为了满足任务链的要求,必须将两个或多个算子设为相同的并行度,并通过本地转发( local for ward)的方式进行连接。相同并行度的one-to-one操作,Fink这样相连的算子链接在一起形成一个task,原来的算子成为里面的 subtask。并行度相同、并且是 one-to-one操作,两个条件缺一不可。但如果我们就想将符合合并的算子给拆开,可以通过添加 slot分组或者添加disableChaining前后都不允许合并。或者使用 startNewChain 只断前面不断后面。

//前后合并都断开
map((_,1)).disableChaining()
//只断前面不断后面,开启一个新链路startNewChain
sum(1).startNewChain()

TM 的数量和 slot数量,决定了并行处理的最大能力,但是不一定程序执行时一定都用到。程序执行时的并行度才是用到的能力。一般情况下,一段代码执行需要的 slot数量,就是并行度最大的算子的并行度。

七、程序与数据流


所有的 Fink程序都是由三部分组成的: Source、 Transformation 和 Sink。Source负责读取数据源,Transformation利用各种算子进行处理加工,Sink负责输出。
【1】在运行时,Fink上运行的程序会被映射成"逻辑数据流”( dataflows),它包含了这三部分。
【2】每一个 dataflow以一个或多个 sources开始以一个或多个 sinks结束。 dataflow类似于任意的有向无环图(DAG)。
【3】在大部分情况下,程序中的转换运算( transformations)跟 dataflow中的算子( operato)是一一对应的关系。Flink 运行时组件_第9张图片
Flink 运行时组件_第10张图片

八、数据流和执行图


1、执行图:Fink中的执行图可以分成四层: StreamGraph-> JobGraph-> ExecutionGraph>物理执行图
StreamGraph是根据用户通过 Stream AP|编写的代码生成的最初的图。用来表示程序的拓扑结构。
JobGraphStreamGraph经过优化后生成了 JobGraph,提交给 JobManager的数据结构。主要的优化为,将多个符合条件的节点 chain在一起作为一个节点。JobManager将JobGraph转化为 ExecutionGraph。showPlan 按钮

ExecutionGraphJobManager根据 JobGraph生成 ExecutionGraphExecutionGraph是 JogRaph的并行化版本,是调度层最核心的数据结构。submit 按钮
物理执行图JobManager根据 Execution Graph对Job进行调度后,在各个TaskManager上部署 task后形成的图,并不是一个具体的数据结构。

2、并行度:一个特定算子的子任务( subtask)的个数被称之为其并行度( parallelism)。一般情况下,一个 stream的并行度,可以认为就是其所有算子中最大的并行度。一个程序中,不同的算子可能具有不同的并行度算子之间传输数据的形式可以是 one-to-one( for warding)的模式也可以是 redistributing的模式,具体是哪一种刑式,取决于算子的种类:
One-to-onestream维护着分区以及元素的顺序(比如ouce和map之间)。这意味着map算子的子任务看到的元素的个数以及顺序跟 source算子的子任务生产的元素的个数、顺序相同。map、 fliter、 flatMap等算子都是one-to-one的对应关系。
Redistributingstream的分区会发生改变。每一个算子的子任务依据所选择的 transformation发送数据到不同的目标任务。例如,kerBy基于 hashCode重分区、而 broadcast和 rebalance会随机重新分区,这些算子都会引起 redistribute过程,而 redistribute过程就类似于 Spark中的 shuffle过程。具体图形化如下:

并行度(Parallelism):一个特定算子的子任务(subtask)的个数被称之为其并行度(Parallelism)。一般情况下,一个 stream 的并行度,可以认为就是其所有算子中最大的并行度。
Flink 运行时组件_第11张图片  

九、并行子任务的分配


完整的体现了任务是如何分配的,之间的数据传输的状态。如下 A-E 五个算子和并行度。A和C都是输入点,B转化操作,D为AC的数据合并,E位输出。slot1.1中的D与E之间就是一个跨分区的操作。
Flink 运行时组件_第12张图片

十、数据传输的形式


一个程序中,不同的算子可能具有不同的并行度。算子之间传输数据的形式可以是one-to-one(forwarding)的模式也可以是redistributing的模式,具体是哪一种形式,取决于算子的种类。
【1】One-to-one:stream 维护者分区以及元素的顺序(比如 source 和 map)之间。这意味着 map 算子的子任务看到的元素的个数以及顺序跟 source算子的子任务生产的元素的个数、顺序相同。map、fliter、flatMap等算子都是one-to-one的对应关系。
【2】Redistributing:stream 的分区会发生改变。每一个算子的子任务依据所选择的 transformation 发送数据到不同的目标任务。例如,keyBy基于 hashCode 重分区、而 broadcast(广播) 和 rebalance(轮询等) 会随机重新分区,这些算子都会引起 redistribute过程,而redistribute 过程就类似与 Spark 中的 shuffle 过程。


  ----架构师资料,关注公众号获取----

你可能感兴趣的:(Flink)