Flink之Flink运行时架构

Flink之Flink运行时架构

目录

1、Flink运行时的组件

2、Flink任务提交流程

3、Flink任务调度流程

1、Flink运行时的组件

 

  •  JobManager(作业管理器) 
    • 控制一个应用程序的主进程,也就是说每个应用程序会被一个不同的JobManager所控制执行
    • JobManager会先接收到要执行的应用程序,这个应用程序包括:作业图(JobGraph)、逻辑数据流图(logical dataFlow graph)和打包了的所有类、库和其他资源的JAR包
    • JobManager会把JobGraph转换成一个物理层面的数据流图,这个图被叫做"执行图"(ExecutionGraph,也就是执行计划),包含了所有可以并发执行的任务。(详情参见:https://zhuanlan.zhihu.com/p/22736103
    • JobManager会向资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot)。一旦它获取了足够资源,就会将执行图分发到真正运行它们的TaskManager上。而在运行过程中Jobmanager会负责中央协调操作,比如检查点(checkpoint)的协调。
  • TaskManager(任务管理器)
    • Flink 的工作进程。通常在Flink中会有多个TaskManager在运行,每个taskManager都包含了一定数量的插槽(slot,是Flink中定义的处理资源的单元)。插槽的数量限制了TaskManager能够执行的任务数量。(注意:TaskManager的数量*每个TaskManager 的slot的数量=整个集群能够提供给这个Job的slot总数,就代表这个集群静态并行计算的最大能力,注意与任务的实际并行度相区分)
    • 启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令之后,TaskManager就会将一个或者多个插槽提供给JobManager调用,JobManager就可以向插槽分配任务(task)来执行了。
    • 在执行过程中,一个TaskManager可以跟其他运行同一应用程序的TaskManager交换数据。
  • ResourceManager(资源管理器)
    • 主要负责任务管理器(TaskManger)的插槽(slot)。
    • Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN,Mesos,K8s以及standalone部署
    • 当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager。如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。
  • Dispatcher(分发器)
    • 可以跨作业运行,它为应用提交提供了REST接口
    • 当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager
    • Dispatcher也会启动一个WEB UI,用来方便地展示和监控作业执行的信息。
    • Dispatche在架构中可能也不是必须的,这个取决于应用提交运行的方式

2、Flink任务提交流程

 

 

 

 Flink on Yarn:Flink提交任务之后,client向HDFS上上传Flink的jar包和配置,之后向Yarn ResourceManager提交任务,ResourceManager分配Container资源并通知对应的NodeManager启动ApplicationMaster,ApplicationMaster启动之后加载Flink的Jar包和配置构建环境,然后启动JobManager,之后ApplicationManster向ResourceManager申请资源启动TaskMnager,ResourceManager分配好Container资源之后,由ApplicationMaster通知资源所在节点的NodeManager启动TaskManager,NodeManager加载Flink的Jar包和配置构建环境并启动TaskManager,TaskManager启动之后向JobManager发生心跳包,并等待JobManager向其分配任务。

3、Flink任务调度流程

  3.1 从API到JobGraph

Flink 四层转化流程

Flink 有四层转换流程,第一层为 Program 到 StreamGraph;第二层为 StreamGraph 到 JobGraph;第三层为 JobGraph 到 ExecutionGraph;第四层为 ExecutionGraph 到物理执行计划。通过对 Program 的执行,能够生成一个 DAG 执行图,即逻辑执行图。如下:

第一部分将先讲解四层转化的流程,然后将以详细案例讲解四层的具体转化。

  • 第一层 StreamGraph 从 Source 节点开始,每一次 transform 生成一个 StreamNode,两个 StreamNode 通过 StreamEdge 连接在一起,形成 StreamNode 和 StreamEdge 构成的DAG。

  • 第二层 JobGraph,依旧从 Source 节点开始,然后去遍历寻找能够嵌到一起的 operator,如果能够嵌到一起则嵌到一起,不能嵌到一起的单独生成 jobVertex,通过 JobEdge 链接上下游 JobVertex,最终形成 JobVertex 层面的 DAG。

  • JobVertex DAG 提交到任务以后,从 Source 节点开始排序,根据 JobVertex 生成ExecutionJobVertex,根据 jobVertex的IntermediateDataSet 构建IntermediateResult,然后 IntermediateResult 构建上下游的依赖关系,形成 ExecutionJobVertex 层面的 DAG 即 ExecutionGraph。

  • 最后通过 ExecutionGraph 层到物理执行层。

Program到StreamGraph的转化

Program 转换成 StreamGraph 具体分为三步:

  • 从 StreamExecutionEnvironment.execute 开始执行程序,将 transform 添加到 StreamExecutionEnvironment 的 transformations。

  • 调用 StreamGraphGenerator 的 generateInternal 方法,遍历 transformations 构建 StreamNode 及 StreamEage。

  注意:并不是所有的transform都能转化成为StreamNode,有一些只是逻辑概念,比如 union、split/select、partition等会被优化成虚拟节点。如下图所示:

  • 通过 StreamEdge 连接 StreamNode。

什么是StreamNode和StreamEdge?

  • StreamNode 是用来描述 operator 的逻辑节点,其关键成员变量有 slotSharingGroup、jobVertexClass、inEdges、outEdges以及transformationUID;

  • StreamEdge 是用来描述两个 operator 逻辑的链接边,其关键变量有 sourceVertex、targetVertex。

StreamGraph 到 JobGraph 的转化

StreamGraph 到 JobGraph 的转化步骤:

  • 设置调度模式,Eager 所有节点立即启动。

  • 广度优先遍历 StreamGraph,为每个 streamNode 生成 byte 数组类型的 hash 值。

  • 从 source 节点开始递归寻找嵌到一起的 operator,不能嵌到一起的节点单独生成 jobVertex,能够嵌到一起的开始节点生成 jobVertex,其他节点以序列化的形式写入到 StreamConfig,然后 merge 到 CHAINED_TASK_CONFIG,再通过 JobEdge 链接上下游 JobVertex。

  • 将每个 JobVertex 的入边(StreamEdge)序列化到该 StreamConfig。

  • 根据 group name 为每个 JobVertext 指定 SlotSharingGroup。

  • 配置 checkpoint。

  • 将缓存文件存文件的配置添加到 configuration 中。

  • 设置 ExecutionConfig。

那么Operator能被Chain到一起的条件是什么呢?

  • 下游节点只有一个输入。

  • 下游节点的操作符不为 null。

  • 上游节点的操作符不为 null。

  • 上下游节点在一个槽位共享组内。

  • 下游节点的连接策略是 ALWAYS。

    • Flink一共有三种连接策略:
      •  ALWAYS(可以与上下游链接,map、flatmap、filter等默认是ALWAYS)
      • HEAD(只能与下游链接,不能与上游链接,Source默认是HEAD)
      • NEVER
  • 上游节点的连接策略是 HEAD 或者 ALWAYS。

  • edge 的分区函数是 ForwardPartitioner 的实例。

  • 上下游节点的并行度相等。

  • 可以进行节点连接操作。

Flink将多个任务链接成一个任务在一个线程中执行,降低线程上下文切换的开销,减小缓存容量,提高系统吞吐量的同时降低延迟。可以通过API设置:

//全局禁用Chain
env.disableOperatorChaining()

//flatmap-->fliter-->map
dataStream.flatmap(...).filter(...).map(...)

//flatmap-X->fliter-X->map,filter节点前后断开
dataStream.flatmap(...).filter(...)。disableChainig().map(...)

//flatmap-->fliter-X->map,map节点单独断开
dataStream.flatmap(...).filter(...).map(...).StartNewChain()

JobGraph 到 ExexcutionGraph 以及物理执行计划

JobGraph 到 ExexcutionGraph 以及物理执行计划的流程:

  • 将 JobGraph 里面的 jobVertex 从 Source 节点开始排序。

  • 在 executionGraph.attachJobGraph(sortedTopology)方法里面,根据 JobVertex 生成 ExecutionJobVertex,在 ExecutionJobVertex 构造方法里面,根据 jobVertex 的 IntermediateDataSet 构建 IntermediateResult,根据 jobVertex 并发构建 ExecutionVertex,ExecutionVertex 构建的时候,构建 IntermediateResultPartition(每一个 Execution 构建 IntermediateResult 数个IntermediateResultPartition );将创建的 ExecutionJobVertex 与前置的 IntermediateResult 连接起来。

  • 构建 ExecutionEdge ,连接到前面的 IntermediateResultPartition,最终从 ExecutionGraph 到物理执行计划。

 3.2 TaskManager 与 Slots

Flink 中每一个 worker(TaskManager)都是一个 JVM 进程,它可能会在独立的线 程上执行一个或多个 subtask。为了控制一个 worker 能接收多少个 task,worker 通 过 task slot 来进行控制(一个 worker 至少有一个 task slot)。 每个 task slot 表示 TaskManager 拥有资源的一个固定大小的子集。假如一个 TaskManager 有三个 slot,那么它会将其管理的内存分成三份给各个 slot。资源 slot 化意味着一个 subtask 将不需要跟来自其他 job 的 subtask 竞争被管理的内存,取而 代之的是它将拥有一定数量的内存储备。需要注意的是,这里不会涉及到 CPU 的隔 离,slot 目前仅仅用来隔离 task 的受管理的内存。 通过调整 task slot 的数量,允许用户定义 subtask 之间如何互相隔离。如果一个 TaskManager 一个 slot,那将意味着每个 task group 运行在独立的 JVM 中(该 JVM 可能是通过一个特定的容器启动的),而一个 TaskManager 多个 slot 意味着更多的 subtask 可以共享同一个 JVM。而在同一个 JVM 进程中的 task 将共享 TCP 连接(基
于多路复用)和心跳消息。它们也可能共享数据集和数据结构,因此这减少了每个 task 的负载。

 

 

共享slot

Flink 不允许属于不同作业的任务共享同一个Slot,但允许属于同一个作业的不同任务共享同一个Slot,因此同一个作业的所有任务可共享同一个Slot。Flink通过CoLocationGroup和SlotSharingGroup管理任务的调度约束关系:

  • CoLocationGroups : 规定哪些任务必须被调度在同一个Slot上运行
  • SlotSharingGroup : 定义哪些任务可以被调度在同一个Slot上运行

如果没有设置的话,Flink默认所有的任务属于同一个SlotSharingGroup为default,可以通过API来强制指定Operator的共享组:

dataStream.map(...).slotSharingGroup("name")

 

posted @ 2020-10-17 02:25  这个小仙女真可爱  阅读(323)  评论(0编辑  收藏  举报