Flink 运行时组件

目录

一、四大组件

二、任务提交流程

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

四、任务调度原理

五、TaskManager 和 Slots

六、任务链

七、程序与数据流

八、数据流和执行图

九、并行子任务的分配

十、数据传输的形式


一、四大组件


JobManager(分配任务,调度checkpoint做快照)、TaskManager(主要干活的)、ResourceManager(资源管理器,分配资源,管理资源)、Dispacher(方便提交任务的接口,WebUI)

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在架构中可能并不是必需的,这取决于应用提交运行的方式;

二、任务提交流程


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


其中ApplicationMaster 启动JobManager 的时候会连带 Flink的 ResourceManager 一块启动。JobManager 会向 Flink 的ResourceManager 申请资源,而 Flink 的RM会向 YARN 的RM申请资源。

四、任务调度原理


运行时状态,Flink Program 生成一个数据流图,经过Client客户端处理之后将其提交给 JobManager,在JobManager 中根据并行度生成一个执行图。就会申请足够的 Task Slot ,最后将任务分配到 TaskSlot中。

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进行共享。

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

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


下面有3个核心数,我们就按照推荐的分配三个 slot,程序例如也就 WordCound的三步操作。

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

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


还要就是程序的最后是输出到文件中,上图就会输出到不同的文件中,因此下面就是讲最后一个任务只分配到一个Slot中,这样保证输出的结果只保存在一个文件中。

一个流处理程序需要的 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)是一一对应的关系。

八、数据流和执行图


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 的并行度,可以认为就是其所有算子中最大的并行度。
  

九、并行子任务的分配


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

十、数据传输的形式


一个程序中,不同的算子可能具有不同的并行度。算子之间传输数据的形式可以是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 过程。


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

猜你喜欢

转载自blog.csdn.net/zhengzhaoyang122/article/details/107050324