赞
踩
——wirte by 橙心橙意橙续缘,
白话系列
————————————————————————————
也就是我在写作时完全不考虑写作方面的约束,完全把自己学到的东西、以及理由和所思考的东西等等都用大白话诉说出来,这样能够让信息最大化的从自己脑子里输出并且输入到有需要的同学的脑中。PS:较为专业的地方还是会用专业口语诉说,大家放心!
白话Flink系列
————————————————————————————
主要是记录本人(国内某985研究生)在Flink基础理论阶段学习的一些所学,更重要的是一些所思所想,所参考的视频资料或者博客以及文献资料均在文末放出.由于研究生期间的课题组和研究方向与Flink接轨较多,而且Flink的学习对于想进入大厂的同学们来说也是非常的赞,所以该系列文章会随着本人学习的深入来不断修改和完善,希望大家也可以多批评指正或者提出宝贵建议。
到底什么是运行时?
——————————————
运行时,也就是runtime,是一个分布式数据流作业执行引擎,按照我的理解就是他是Flink客户端从提交任务,然后这个任务生成JobGraph,到JobManage然后通过调度taskmanage执行一直到结束的整个过程中所需要的全部,包括一些必要的组件(静态),任务调度,资源管理,分布式通信,节点同步(动态)等一系列的过程。所以对runtime这一块必须要有清晰深刻的了解,这对于后续进行一些高级的Flink优化操作十分重要!!!
根据下面的图我们可以看到,Runtime是Flink整体架构中的一部分,我们可以看到它起一个承接API层和底层执行环境的这么一个作用。
上图是Flink的整体架构图,可以看到Runtime针对不同的环境和API都是统一的,也就是说不同作业在不同环境下的执行流程是一致的。
针对不同的执行环境(云环境、YARN,k8s等),Flink 提供了一套统一的分布式作业执行引擎,也就是 Flink Runtime 这层。Flink 在 Runtime 层之上提供了 DataStream 和 DataSet 两套 API,分别用来编写流作业与批作业,以及一组更高级的 API 来简化特定作业的编写。(现在最新的Flink1.12已经实现了流批一体的落地,这块会在后续专门研究)
所以Runtime层到底长什么样?
上图就是Runtime层的架构图了,它采用了标准 master-slave 的结构,其中左侧白色圈中的部分即是 master,它负责管理整个集群中的资源和作业;而右侧的两个 TaskManager 则是 Slave,负责提供具体的资源并实际执行作业。
其中可以看到,Master 部分又包含了三个组件,即 Dispatcher、ResourceManager 和 JobManager。其中,Dispatcher 负责接收用户提供的作业,并且负责为这个新提交的作业拉起一个新的 JobManager 组件。ResourceManager 负责资源的管理,在整个 Flink 集群中只有一个 ResourceManager。JobManager 负责管理作业的执行,在一个 Flink 集群中可能有多个作业同时执行,每个作业都有自己的 JobManager 组件。这三个组件都包含在 AppMaster 进程中。
这张图我强烈建议大家在最后在回顾一下,可以看到客户端是提交了2个东西的,1个是app来告诉集群资源管理器启动AM,另一个是要具体的job来提供是分发器,或者说是为了提供给jobManager。
这里我们先搞清楚2个概念。
Flink Application
:指的是一个使用了Flink API编写的java Application,里面可能包含了多个Flink job。Flink job
:指的是被Flink Application中.execute()所提交的,包含1个完整的DAG处理过程,即从source-sink的完整处理流程的程序。Flink的组件主要是四大组件JobManage,TaskManager,Resource Manager(资源管理器) 和Dispacher(分发器),这在我们刚刚的runtime架构中已经体现出来了,现在来具体讲一讲它们是干嘛的
就像它名字对应的一样,任务管理器,也就是用户从客户端Client提交一个应用程序,也就是一个作业(job)的控制主进程,它只有一个(位于master节点上,Flink启动后可以使用jps指令查看的那一个java进程就是了),就算配置了HA高可用,可能有多个jobManager来进行stand by,但是集群在具体的某一时刻真正起作用的也是只有1个Job Manager进程的。
首先,它会接收到所分配的应用程序,里面包括:在Client上根据我们的代码生成的作业图(JobGraph)、逻辑数据流图(logical dataflow graph)和打包了所有的类、库和其它资源的 JAR 包。
然后,JobManager 会把 JobGraph 转换成一个物理层面的数据流图,这个图被叫做 “执行图”(ExecutionGraph),包含了所有可以并发执行的任务。
这些图的转换会在后续博文中具体讲解。这里可以这样理解,JobGraph就是假设代码中所有算子的并行度为1,也就是不考虑并行度生成的DAG图,而执行图,顾名思义是要用于具体执行的,而Flink最大的特点就是它是一个分布式系统,他是要有并发的,而这个并发如何体现(后续也有讲解),对我们来说最高层也就是并行度的设置,所以执行图会结合并行度来生成,假如map算子有3个并行度,那么对于执行图来说,里面就会有3个map结点,机器只有根据执行图它才知道要怎么去执行,也就是该把哪些task放到slot里,或者说放到哪个slot里,也就是说执行图就是taskmanger执行作业的图纸。
最后,就要调度task进行执行了,在此之前我们肯定需要资源来支持,jobManager如何知道现在集群上哪里有资源呢?它就需要向resourceManager去请求执行任务必要的资源,也就是Slot,当它请求到了所需的资源,它就会把上步生成的执行图(图纸)发送给要干活的TaskManager。
CheckPoint所需—由于分布式集群的特点导致某个节点出现问题可能会影响到其他节点的正常工作,所以都会有容错机制,而CheckPoint检查点也就是Flink中用于进行容错的结构,所以对于1个job来说,JobManager就要承担起这个重任了,比如说到某个特定时刻要进行状态的存储,在出错的时候要进行数据的恢复等等(具体的容错讲解将在后续章节放出)
这里先这样对每个组件的功能进行理解,不用太理清他们的顺序,后续会讲解整个Job的执行流程,这里更像是在预热。
顾名思义,也就是管理任务(Task)的工作进程,它一般有多个,分别运行在Flink集群的每个slave节点上,它更像是一个工人,而我们知道分布式系统最大的特点也就是这种主从结构,1主多从,所以一般的Flink集群都会有多个TaskManager运行着。对于每个TaskManager最基本要了解的就是它上面有很多的插槽(Slot),Slot具体的定义后续放出,我们这里理解Slot也就是一堆资源(CPU和内存),所以Task只有被放在Slot里它才可以获得所需的资源来进行执行,而同一TaskManager,也就是同一台机器上的不同的Slot对应着不同的线程(多线程概念),而这个整体也就构成了我们的TaskManger。
资源管理器,故名思议,是用来管理Flink集群上的资源的,什么是资源?也就是计算资源,提供计算机进行逻辑运算所必须的东西,像CPU,内存等。那资源管理器是怎么管理资源的呢?Flink里为每个TaskManager也就是干活儿的人都设置了1个叫做Slot的东西。这里给出一个Slot的标准定义:Flink中定义的处理资源的最小单元,所以也就是说资源管理器其实管理的就是插槽Slot。
分发器,很简单,也就是当用户提交了一个作业以后,他会把这个作业转交给相应的JobManager来管理。
其实除了上述的四大组件,还有1个组件就是Client,Client也就是用户提交Job的地方,它可以运行在任何与JobManager有通信的机器上。
下面这个图很好地解释了运行时架构中的几大组件是怎么工作的
首先,分发器接收到了用户提交应用程序,然后启动一个JobManager。
在运行过程中的这个JobManager不同于我们在配置集群的时候的静态的概念,静态的JobManager更像是指Master节点,而这里指的则是控制1个Job的主进程,只要有作业在执行,那么就会有一个对应的JobManager进程在工作。
然后,JobManager就要像资源管理器请求执行作业所必须的资源也就是Slot了,这时候资源管理器去启动TaskManager,然后和TaskManager进行交涉并发出资源调度指令。
最后,资源申请到以后,就是JobManager和TaskManager之间的事情了,JobManager把要执行的Task分发到TaskManager对应的Slot中进行执行,然后在执行过程中还会交互一些信息,直到结束。
整个过程还是非常简单直观的,比较抽象没有具体到每一步底层在做什么,但是在这一块我们要明确2点,(1)JobManager是分发器接收到1个Job才启动的,(2)TaskManager是ResourceManager收到JobManager的资源请求后启动的。
也就是在Flink集群上需要安装有Hadoop和HDFS,并且在提交Flink作业时Hadoop处于运行状态,那么整个Flink的资源管理就会被YARN接管过来
这里的图主要使用了B站尚硅谷教程中的图,可以看到他这里吧分发器和资源管理器给取消掉了,其实它们作为Flink的Runtime基本架构中的组件还是存在于AppMaster中的,只不过没有体现,具体可以参考上面阿里云的那张图。
我们可以看到提交的过程大致相同,主要来分析一下基于YARN资源管理的作业提交过程和Flink Standlone模型的作业提交过程有什么不同?
这里在最终详细地说一下任务提交的过程,大家好好理解。
当用户提交作业的时候,提交脚本会首先启动一个 Client进程负责作业的编译与提交。它首先将用户编写的代码编译为一个 JobGraph,在这个过程,它还会进行一些检查或优化等工作,例如判断哪些 Operator 可以 Chain 到同一个 Task 中。然后,Client 将产生的 JobGraph 提交到集群中执行。此时有两种情况,一种是类似于 Standalone 这种 Session 模式,AM 会预先启动,此时 Client 直接与 Dispatcher 建立连接并提交作业即可。另一种是 Per-Job 模式,AM 不会预先启动,此时 Client 将首先向资源管理系统 (如Yarn、K8S)申请资源来启动 AM,然后再向 AM 中的 Dispatcher 提交作业。
上图是Fllink Runtime作业执行的2种模式。Per-job 模式下整个 Flink 集群只执行单个作业,即每个作业会独享 Dispatcher 和 ResourceManager 组件。此外,Per-job 模式下 AppMaster 和 TaskManager都是按需申请的,用多少就启动多少。因此,Per-job 模式更适合运行执行时间较长的大作业,这些作业对稳定性要求较高,并且对申请资源的时间不敏感。与之对应,在 Session 模式下,Flink 预先启动 AppMaster 以及一组 TaskManager,然后在整个集群的生命周期中会执行多个作业。可以看出,Session 模式更适合规模小,执行时间短的作业。
当作业到 Dispatcher 后,Dispatcher 会首先启动一个 JobManager 组件,然后 JobManager 会向 ResourceManager 申请资源来启动作业中具体的任务。这时根据 Session 和 Per-Job 模式的区别, TaskManager可能已经启动或者尚未启动。如果是前者,此时 ResourceManager 中已有记录了 TaskManager注册的资源,可以直接选取空闲资源进行分配。否则,ResourceManager 也需要首先向外部资源管理系统申请资源来启动 TaskManager,然后等待 TaskManager注册相应资源后再继续选择空闲资源进程分配。ResourceManager 选择到空闲的 Slot 之后,就会通知相应的 TaskManager “将该 Slot 分配分 JobManager XX ”,然后 TaskManager进行相应的记录后,会向 JobManager 进行注册。JobManager 收到 TaskManager注册上来的 Slot 后,就可以实际提交 Task 了。
TaskManager收到 JobManager 提交的 Task 之后,会启动一个新的线程来执行该 Task。Task 启动后就会开始进行预先指定的计算,并通过数据 Shuffle 模块互相交换数据。
下面这个图应该大家都见过很多次了,它里面较于我们刚刚上面的图更加细致了,这里主要忽略了资源管理器,只展示了JobManager和TaskManager具体在做什么。
1、Program Code:我们编写的 Flink 应用程序代码
2、Job Client:Job Client 不是 Flink 程序执行的内部部分,但它是任务执行的起点。Job Client 负责接受用户的程序代码,然后创建数据流,将数据流提交给 Job Manager 以便进一步执行。执行完成后,Job Client 将结果返回给用户
3、Job Manager:主进程(也称为作业管理器)协调和管理程序的执行。它的主要职责包括安排任务,管理 checkpoint ,故障恢复等。机器集群中至少要有一个 master,master 负责调度 task,协调 checkpoints 和容灾,高可用设置的话可以有多个 master,但要保证一个是 leader, 其他是 standby; Job Manager 包含 Actor system、Scheduler、Check pointing 三个重要的组件
4、Task Manager:从 Job Manager 处接收需要部署的 Task。Task Manager 是在 JVM 中的一个或多个线程中执行任务的工作节点。任务执行的并行性由每个 Task Manager 上可用的任务槽(Slot 个数)决定。每个任务代表分配给任务槽的一组资源。例如,如果 Task Manager 有四个插槽,那么它将为每个插槽分配 25% 的内存。可以在任务槽中运行一个或多个线程。同一插槽中的线程共享相同的 JVM。
同一 JVM 中的任务共享 TCP 连接和心跳消息。Task Manager 的一个 Slot 具有固定的内存,注意 Slot 只对内存隔离,没有对 CPU 隔离
。默认情况下,Flink 允许子任务共享 Slot,即使它们是不同 task 的 subtask,只要它们来自相同的 job。这种共享可以有更好的资源利用率。
再总结一下里面的核心要点。
Client与JobManager传输的是与job有关的数据,包括JobGraph,jar包等,以及提交作业,取消作业和返回的作业结果以及统计信息等数据
JobManager与TaskManager除了传输所要执行的Task,包括提到过的执行图等信息,还包括一些心跳和统计信息。
这里不同于之前的是还可以看到Flink底层的分布式计算和消息传递是通过Akka的Actor System(演员系统)来实现的,数据的传递是基于Netty框架实现的,Akka是什么呢?
Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用,使构建高并发的分布式应用更加容易。Akka是基于Actor模型的实现,而Actor由状态(state)、行为(Behavior)和邮箱(mailBox)三部分组成。
状态(state):Actor中的状态指的是Actor对象的变量信息,状态由Actor自己管理,避免了并发环境下的锁和内存原子性等问题
行为(Behavior):行为指定的是Actor中计算逻辑,通过Actor接收到消息来改变Actor的状态
邮箱(mailBox):邮箱是Actor和Actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送方Actor消息,接受方Actor从邮箱队列中获取消息
它主要有这么几个特点:异步通信,高可用,高性能,高并发。
本章节主要是讲述了宏观上的Flink的1个任务提交以后,各个组件之间是怎么配合协调工作的,在里面其实我们有几个点没有讲的很清楚,但是确实非常重要的几个点。(1) 作业的DAG图从生成到最后物理层面去执行到底是怎么转化的?这里呢只是在Client和JobMnaager那部分粗略的提到过一点(2)JobManager具体是怎么把一个Task调度给Slot进行执行的呢?也就是说1个job过来要用几个Slot,用的这几个Slot里执行的任务又分别是什么呢?这2点还需要后续专门设置章节来好好梳理!
《阿里云Apache Flink 进阶(一):Runtime 核心机制剖析》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。