Flink 运行时架构主要包括四个不同的组件,它们会在运行流处理应用程序时协同工作:作业管理器(JobManager)资源管理器(ResourceManager)任务管理器(TaskManager)以及分发器(Dispatcher)。因为Flink是用 Java 和 Scala 实现的,所以所有组件都会运行在 Java 虚拟机上。每个组件的职责如下:

  • 作业管理器(JobManager)
    控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的 JobManager 所控制执行。JobManager 会先接收到要执行的应用程序,这个应用程序会包括:作业图(JobGraph)、逻辑数据流图(logic dataflow graph) 和 打包了所有的类 、库 和 其它资源的 JAR包。 JobManager 会把 JobGraph 转换成一个物理层面的数据流图,这个图被叫做 "执行图" (ExecutionGraph),包含了所有可以并发执行的任务。 JobManager 会向资源管理器 (ResourceManager) 请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot)。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的 TaskManager 上。而在运行过程中,JobManager 会负责所有需要中央协调的操作,比如说检查点 (checkpoints)的协调。
  • 资源管理器(ResourceManager)
    主要负责管理任务管理器(TaskManager)的插槽(slot), TaskManager 插槽是 Flink 中定义的处理资源单元。 Flink 为不同的环境和资源管理工具提供了 不同资源管理器,比如 YARN、Mesos、K8s,以及standalone 部署。当 JobManager 申请插槽资源时,ResourceManager 会将有空闲插槽的 TaskManager 分配给 JobManager。如果ResourceManager 没有足够的插槽来满足 JobManager 的请求,它还可以向资源提供平台发起会话,以提供了启动 TaskManager 进程的容器。另外, ResourceManager 还负责终止空闲的 TaskManager, 释放计算资源。
  • 任务管理器(TaskManager)
    Flink 中的工作进程。通常在Flink 中会有多个 TaskManager 运行,每一个 TaskManager 都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量。启动之后,TaskManager 会向资源管理器注册它的插槽; 收到资源管理器的指令后, TaskManager 就会将一个或者多个插槽提供给 JobManager 调用。JobManager 就可以向插槽分配任务(tasks) 来执行了。在执行过程中,一个TaskManager可以跟其它运行同一应用程序的 TaskManager 交换数据。
  • 分发器(Dispatcher)
    可以跨作业运行,它为应用提交提供了 REST 接口。当一个应用被提交执行时,分发器就会启动并将 应用移交给一个 JobManager。由于是 REST 接口,所以Dispatcher 可以作为集群的一个HTTP接入点,这样就能够不受防火墙阻挡。 Dispatcher 也会启动一个 Web UI , 用来方便地展示和监控作业执行的信息。 Dispatcher 在架构中可能并不是必需的,这取决于应用 提交运行的方式。

任务提交流程

Flink main任行任务Java 打包 flink任务需要哪些部分_并行度

上图是从一个较为高层级的视角,来看应用中各组件的交互写作。如果部署的集群环境不同(例如 YARN、Mesos、Kubernetes、standalone 等), 其中一些步骤可以被省略,或者是有些组件会运行在同一个JVM进程中。具体地,如果我们将 Flink 集群部署到 YARN 上,那么就会有如下的提交流程:

Flink main任行任务Java 打包 flink任务需要哪些部分_插槽_02

上图其实Flink内部有ResourceManager,但是这个ResourceManager不管事,它把资源管理的权限交给了外部的Yarn上的ResourceManager,JobManager拿到Job后要向Yarn-ResourceManager申请资源,Yarn-ResourceManager 会告诉JobManager哪个TaskManager上有资源,然后由ApplicationMaster通知资源所在的节点的NodeManager启动TaskManager,Nodemanager会加载Flink的jar包和配置构建环境,启动之后向JobManager发送心跳包,等JobManager向其分配任务。(Job模式)

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 向其分配任务。

任务调度原理 


Flink main任行任务Java 打包 flink任务需要哪些部分_并行度_03

客户端不是运行时和程序执行的一部分,但是它是用于准备并发送 dataflow(JobGraph) 给 Master(JobManager), 然后, 客户端断开连接 或者维持连接以等待接收计算结果。

当 Flink 集群启动后,首先会启动一个JobManager或多个TaskManager。由 Client 提交任务给 JobManager, JobManager 再调度任务到 各个TaskManager 去执行, 然后 TaskManager 把心跳和统计信息汇报给JobManager。 TaskManager 之间以流的形式 进行数据的传输。 上述三者均为独立的 JVM 进程。

Client 为提交 job 的客户端,可以是运行在 任何机器上(与 JobManager 环境联通即可)。提交 Job 后, Client 可以结束进程(Streaming 的任务), 也可以不结束并等待结果返回。
JobManager 主要负责调度 Job 并协调 Task 做 checkpoint, 职责上很像 Storm 的 Nimbus。从 Client 处接收到 Job 和 JAR 包等资源后,就会生成优化后的 执行计划,并以 Task 的单元调度到各个 TaskManager去执行。
TaskManager 在启动的时候就设置好了 槽位数 (Slot), 每个 slot 能启动一个 Task, Task 为线程。 从 JobManager 处接收需要部署的 Task,部署启动后, 与自己的上游建立 Netty 连接,接收数据并处理。

  • 怎样实现并行计算:多线程,不同的任务分配到不同的线程,不同的线程应该在不同的slot。
  • 并行的任务,需要占用多少个slot?:在我们提交一个Job之后,划分任务,它占用的slot个数跟所有任务中最大那个并行度有关系。(即使有7个任务,但是只需要3个 slot就能运行起来。)
  • 一个流处理程序到底包含多少个任务:可以在代码中设置Slot共享组,每个共享组中最大的并行度相加就是总任务的个数。占用的slot 如果设置了Slot共享组,就和组数有关系, = 组数。

并行度(Parallelism):一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism),一般情况下,一个 stream 的并行度,可以认为就是其所有算子中最大的并行度。

Flink main任行任务Java 打包 flink任务需要哪些部分_插槽_04

TaskManager 和 Slots

Flink main任行任务Java 打包 flink任务需要哪些部分_插槽_05

并行度设置是当前并行执行的子任务个数,而并行执行的子任务要分布在不同的slot上去执行,slot就是执行一个独立线程所需要的资源(cpu+内存)的最小单位。每一个slot的内存是隔离开的,但是cpucore是共享的,假如有2个slot,1个cpu ,那这个cpu就要发生时间片轮转,被这两个线程分别调用。按照当前 taskManager的核心core 来设置slot数,最好保证 一个slot 能够拥有 一个core。

Flink main任行任务Java 打包 flink任务需要哪些部分_插槽_06

  • 默认情况下,Flink允许子任务共享 slot,即使它们是不同的任务的子任务。这样的结果是,一个slot可以保存作业的整个管道。
  • TaskSlot是静态的概念,是指 TaskManager 具有并发执行的能力。

能放在一个slot上去执行,必须是前后发生的不同的任务,才可以共享一个slot。

Flink main任行任务Java 打包 flink任务需要哪些部分_并行度_07

但为什么上图有 用到 5个Slot?是因为在代码中设置了slot共享组,针对每一步操作每一个算子设置共享组,组名相同的操作在同一个组内,组内任务都共用Slot
后一个操作算子不设置共享组名,则默认和前一个操作算子是一组。 在不同的slot上执行是不同的任务。

Flink main任行任务Java 打包 flink任务需要哪些部分_应用程序_08

任务需要的slot数量和最大并行度有关

Flink main任行任务Java 打包 flink任务需要哪些部分_并行度_09

具体示例

Flink main任行任务Java 打包 flink任务需要哪些部分_并行度_10


Flink main任行任务Java 打包 flink任务需要哪些部分_插槽_11