Apache Flink——运行时架构
一、Flink运行时组件
Flink 的运行时架构中,最重要的就是两大组件:作业管理器(JobManger)和任务管理器(TaskManager)。对于一个提交执行的作业,JobManager 是真正意义上的“管理者”(Master),负责管理调度,所以在不考虑高可用的情况下只能有一个;而 TaskManager 是“工作者”(Worker、Slave),负责执行任务处理数据,所以可以有一个或多个。
Flink 的作业提交和任务处理系统其实客户端并不是处理系统的一部分,它只负责作业的提交。具体来说,就是调用程序的 main 方法,将代码转换成“数据流图”(Dataflow Graph),并最终生成作业图(JobGraph),一并发送给 JobManager。提交之后,任务的执行其实就跟客
户端没有关系了;我们可以在客户端选择断开与 JobManager 的连接, 也可以继续保持连接。可以在命令提交作业时,加上的-d 参数,就是表示分离模式(detached mode),也就是断开连接。
当然,客户端可以随时连接到 JobManager,获取当前作业的状态和执行结果,也可以发
送请求取消作业。
JobManager 和 TaskManagers 可以以不同的方式启动:
- 作为独立(Standalone)集群的进程,直接在机器上启动
- 在容器中启动
- 由资源管理平台调度启动,比如 YARN、K8S
TaskManager 启动之后,JobManager 会与它建立连接,并将作业图(JobGraph)转换成可执行的“执行图”(ExecutionGraph)分发给可用的 TaskManager,然后就由 TaskManager 具体执行任务。
1.1 作业管理器(JobManager)
JobManager 是一个 Flink 集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被唯一的 JobManager 所控制执行。当然,在高可用(HA)的场景下,可能会出现多个 JobManager;这时只有一个是正在运行的领导节点(leader),其他都是备用节点(standby)。JobManger 又包含 3 个不同的组件
1.1.1 JobMaster
obMaster 是 JobManager 中最核心的组件,负责处理单独的作业(Job)。所以JobMaster和具体的 Job 是一一对应的,多个 Job 可以同时运行在一个 Flink 集群中,每个 Job 都有一个自己的 JobMaster。需要注意在早期版本的 Flink 中,没有 JobMaster 的概念;而 JobManager的概念范围较小,实际指的就是现在所说的 JobMaster。
在作业提交时,JobMaster 会先接收到要执行的应用。这里所说“应用”一般是客户端提交来的,包括:Jar 包,数据流图(dataflow graph),和作业图(JobGraph)。
JobMaster 会把 JobGraph 转换成一个物理层面的数据流图,这个图被叫作“执行图”(ExecutionGraph),它包含了所有可以并发执行的任务。 JobMaster 会向资源管理器(ResourceManager)发出请求,申请执行任务必要的资源。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的 TaskManager 上。而在运行过程中,JobMaster 会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调。
1.1.2 资源管理器(ResourceManager)
ResourceManager 主要负责资源的分配和管理,在 Flink 集群中只有一个。所谓“资源”,主要是指 TaskManager 的任务槽(task slots)。任务槽就是 Flink 集群中的资源调配单元,包含了机器用来执行计算的一组 CPU 和内存资源。每一个任务(Task)都需要分配到一个 slot 上执行。
这里注意要把 Flink 内置的 ResourceManager 和其他资源管理平台(比如 YARN)的ResourceManager 区分开。
Flink 的 ResourceManager,针对不同的环境和资源管理平台(比如 Standalone 部署,或者YARN),有不同的具体实现。在 Standalone 部署时,因为 TaskManager 是单独启动的(没有Per-Job 模式),所以 ResourceManager 只能分发可用 TaskManager 的任务槽,不能单独启动新TaskManager。
而在有资源管理平台时,就不受此限制。当新的作业申请资源时,ResourceManager 会将有空闲槽位的 TaskManager 分配给 JobMaster。如果 ResourceManager 没有足够的任务槽,它还可以向资源提供平台发起会话,请求提供启动 TaskManager 进程的容器。另外,ResourceManager 还负责停掉空闲的 TaskManager,释放计算资源。
1.1.3 分发器(Dispatcher)
Dispatcher 主要负责提供一个 REST 接口,用来提交应用,并且负责为每一个新提交的作业启动一个新的 JobMaster 组件。Dispatcher 也会启动一个 Web UI,用来方便地展示和监控作业执行的信息。Dispatcher 在架构中并不是必需的,在不同的部署模式下可能会被忽略掉。
1.2 任务管理器(TaskManager)
TaskManager 是 Flink 中的工作进程,数据流的具体计算就是它来做的,所以也被称为“Worker”。Flink 集群中必须至少有一个 TaskManager;当然由于分布式计算的考虑,通常会有多个 TaskManager 运行,每一个 TaskManager 都包含了一定数量的任务槽(task slots)。Slot是资源调度的最小单位,slot 的数量限制了 TaskManager 能够并行处理的任务数量。
启动之后,TaskManager 会向资源管理器注册它的 slots;收到资源管理器的指令后,TaskManager 就会将一个或者多个槽位提供给 JobMaster 调用,JobMaster 就可以分配任务来执行了。
在执行过程中,TaskManager 可以缓冲数据,还可以跟其他运行同一应用的 TaskManager交换数据。
二、任务提交流程
- 1、 一般情况下,由客户端(App)通过分发器提供的 REST 接口,将作业提交给JobManager。
- 2、由分发器启动 JobMaster,并将作业(包含 JobGraph)提交给 JobMaster。
- 3、JobMaster 将 JobGraph 解析为可执行的 ExecutionGraph,得到所需的资源数量,然后向资源管理器请求资源(slots)。
- 4、资源管理器判断当前是否由足够的可用资源;如果没有,启动新的 TaskManager。
- 5、TaskManager 启动之后,向 ResourceManager 注册自己的可用任务槽(slots)。
- 6、资源管理器通知 TaskManager 为新的作业提供 slots。
- 7、TaskManager 连接到对应的 JobMaster,提供 slots。
- 8、JobMaster 将需要执行的任务分发给 TaskManager。
- 9、TaskManager 执行任务,互相之间可以交换数据。
2.1 独立模式(Standalone)
- 1、一般情况下,由客户端(App)通过分发器提供的 REST 接口,将作业提交给JobManager。
- 2、由分发器启动 JobMaster,并将作业(包含 JobGraph)提交给 JobMaster。
- 3、JobMaster 将 JobGraph 解析为可执行的 ExecutionGraph,得到所需的资源数量,然后向资源管理器请求资源(slots)。
- 4、资源管理器直接向已有的 TaskManager 要求资源,启动新的 TaskManager。
- 5、TaskManager 启动之后,向 ResourceManager 注册自己的可用任务槽(slots)。
- 6、资源管理器通知 TaskManager 为新的作业提供 slots。
- 7、TaskManager 连接到对应的 JobMaster,提供 slots。
- 8、JobMaster 将需要执行的任务分发给 TaskManager。
- 9、TaskManager 执行任务,互相之间可以交换数据。
2.2 YARN集群
2.2.1 会话(Session)模式
在会话模式下,我们需要先启动一个 YARN session,这个会话会创建一个 Flink 集群。
这里只启动了 JobManager,而 TaskManager 可以根据需要动态地启动。在 JobManager 内部,由于还没有提交作业,所以只有 ResourceManager 和 Dispatcher 在运行
- 1、客户端通过 REST 接口,将作业提交给分发器。
- 2、分发器启动 JobMaster,并将作业(包含 JobGraph)提交给 JobMaster。
- 3、JobMaster 向资源管理器请求资源(slots)。
- 4、资源管理器向 YARN 的资源管理器请求 container 资源。
- 5、YARN 启动新的 TaskManager 容器。
- 6、TaskManager 启动之后,向 Flink 的资源管理器注册自己的可用任务槽。
- 7、资源管理器通知 TaskManager 为新的作业提供 slots。
- 8、TaskManager 连接到对应的 JobMaster,提供 slots。
- 9、JobMaster 将需要执行的任务分发给 TaskManager,执行任务。
2.2.2 单作业(Per-Job)模式
在单作业模式下,Flink 集群不会预先启动,而是在提交作业时,才启动新的 JobManager。
- 1、客户端将作业提交给 YARN 的资源管理器,这一步中会同时将 Flink 的 Jar 包和配置上传到 HDFS,以便后续启动 Flink 相关组件的容器。
- 2、YARN 的资源管理器分配 Container 资源,启动 Flink JobManager,并将作业提交给JobMaster。这里省略了 Dispatcher 组件。
- 3、JobMaster 向资源管理器请求资源(slots)。
- 4、资源管理器向 YARN 的资源管理器请求 container 资源。
- 5、YARN 启动新的 TaskManager 容器。
- 6、TaskManager 启动之后,向 Flink 的资源管理器注册自己的可用任务槽。
- 7、资源管理器通知 TaskManager 为新的作业提供 slots。
- 8、TaskManager 连接到对应的 JobMaster,提供 slots。
- 9、JobMaster 将需要执行的任务分发给 TaskManager,执行任务。
2.2.3 应用(Application)模式
应用模式与单作业模式的提交流程非常相似,只是初始提交给 YARN 资源管理器的不再是具体的作业,而是整个应用。一个应用中可能包含了多个作业,这些作业都将在 Flink 集群中启动各自对应的 JobMaster。
三、任务调度原理
flink的任务调度原理:Flink中的执行资源通过任务槽(Task Slots)来定义。每个TaskManager都有一个或多个任务槽,每个槽都可以运行一个并行任务管道(pipeline of parallel tasks)。管道由多个连续任务组成,例如MapFunction的第n个并行实例以及ReduceFunction的第n个并行实例。
考虑一个带有数据源,MapFunction和ReduceFunction的程序。源和MapFunction以4的并行度(parallelism)执行,而ReduceFunction以3的并行度执行。管道由序列Source - Map - Reduce组成。在具有2个TaskManagers且每个具有3个插槽的群集上,程序将按如下所述执行。
3.1 TaskManager 和 Slots
-
1、Flink中每一个 Taskmanageri都是一个 JMM进程,它可能会在独立的线程上执行 一个或多个 subtask。
-
2、为了控制一个 Taskmanageri能接收多少个task, Taskmanager通过 task slot来进行控制(一个 Taskmanager至少有一个slot)
- 3、默认情况下,Fink允许子 任务共享slot,即使它们是不同任务的子任务。这样的结果是, 一个slot可以保存作业的整个管道。
- 4、Task Slot是静态的概念,是指 Taskmanager具有的并发执行能力
3.2 程序与数据流(DataFlow)
- 1、所有的 Flink程序都是由三部分组成的: Source、 Transformation和 Sink。
- 2、Source负责读取数据源, Transformation利用各种算子进行处理加工,Sink负责输出。
- 3、在运行时, Flink上运行的程序会被映射成 “逻辑数据流”( dataflows),它包含了这三部分。
- 4、每一个 dataflow以 一个或多个 Sources开始以 一个或多个 sinks结束。 dataflow类以于任意的有向无环图(DAG)。
- 5、在大部分情况下,程序中的 转换运算( transformations)跟 dataflow中的算子。
3.3 执行图(ExecutionGraph)
Flink中的执行图可以分成四层:
Streamgraph -> Jobgraph -> Executiongraph -> 物理执行图
- Streamgraph:是根据用户通过 Stream API编写的代码生成的最初的图。用来表示程序的 拓扑结构。
- Jobgraph:Streamgraph经过优化后生成了 Jobgraph,提交给 Jobmanager的数据结构。主要的优化为,将多个符合条件的节点 chain在一起作为一个节点Execution Graph:Jobmanager根据 Jobgraph生成
- ExecutiongraphExecution Graph:是 Job Graphi的并行化版本,是调 度层最核心的数据结构。
- 物理执行图: Jobmanager根据 Executiongraph对Job进行调度后,在各个Taskmanager上部署Task后形成的“ 图”,并不是一个具体的数据结构。
3.4 并行度(Parallelism)
- 1、特定算子的子任务( subtask)的个数被称之为其并行度( parallelism)般情况下,一个 stream的并行度,可以认为就是其所有算子中最大的并行度。
- 2、一个程序中,不同的算子可能具有不同的并行度。
- 3、算子之间传输数据的形式可以是 one-to-one( (forwarding)的模式也可以是 redistributing的模式,具体是哪一种形式,取決于算子的种类。
- 4、One-to-one: stream维护着分区以及元素的顺序(比如 Sources和map之间)。这意味着map算子的子任务看到的元素的个数以及顺序跟 Source算子的子任务生产的元素的个数、顺序相同。map、 fliter.、 flatmap等算子都是 one-to-one的对应关系。
- 5、Redistributing: stream的分区会发生改变。每一个算子的子任务依据所选择的transformation发送数据到不同的目标任务。例如, keyby基于 hash Code重分区、而 broadcast和 rebalance会随机重新分区,这些算子都会引起distributer过程,而 redistribute过程就类似于 Spark中的 shuffle过程。
3.5 任务链(Operator Chains)
- 1、Flink采用了一种称为任务链的优化技术,可以在特定条件下减少本地通信的开销。为了满足任务链的要求 ,必须将两个或多个算子设为相同的并行度,并通过本地转发( ocal forward)的方式进行连接。
- 2、相同并行度的one-to-one操作, Flink这样相连的算子链接在一起形成一个task,原来的算子成为里面的 subtask并行度相同、并且是one-to-one操作,两个条件缺一不可。
参考:
https://blog.csdn.net/m0_61607827/article/details/123211641
https://blog.csdn.net/weixin_45417821/article/details/124049022
https://blog.csdn.net/weixin_45417821/article/details/124050622