【白话Flink基础理论】Flink运行时(Runtime)架构(四)作业提交的深度过程&核心DAG结构的转变

——wirte by 橙心橙意橙续缘,

前言

白话系列
————————————————————————————
也就是我在写作时完全不考虑写作方面的约束,完全把自己学到的东西、以及理由和所思考的东西等等都用大白话诉说出来,这样能够让信息最大化的从自己脑子里输出并且输入到有需要的同学的脑中。PS:较为专业的地方还是会用专业口语诉说,大家放心!

白话Flink系列
————————————————————————————
主要是记录本人(国内某985研究生)在Flink基础理论阶段学习的一些所学,更重要的是一些所思所想,所参考的视频资料或者博客以及文献资料均在文末放出.由于研究生期间的课题组和研究方向与Flink接轨较多,而且Flink的学习对于想进入大厂的同学们来说也是非常的赞,所以该系列文章会随着本人学习的深入来不断修改和完善,希望大家也可以多批评指正或者提出宝贵建议。


到底什么是运行时?
——————————————
运行时,也就是RUNTIME,是一个分布式数据流作业执行引擎,按照我的理解就是他是Flink客户端从提交任务,然后这个任务生成JobGraph,到JobManage然后通过调度taskmanage执行一直到结束的整个过程中所需要的全部,包括一些必要的组件(静态),任务调度,资源管理,分布式通信,数据传输、节点同步(动态)等一系列的过程。所以对runtime这一块必须要有清晰深刻的了解,这对于后续进行一些高级的Flink优化操作十分重要!!!

说在前面
————————————————————————————————

通过Runtime架构部分前三节的讲解,我们已经对Runtime层Task的执行过程有了清晰的认识,那么本节主要讲什么呢?

讲的就是贯穿Flink Job执行Task全过程中的各种DAG图的转化,因为不管是从最初的Client还是到最后的Slot,task的执行其实就是这些DAG图的转换过程,因为它们都是通过DAG(图纸)来进行自己的工作,虽然前面可能我们对于在JobManager所进行的JobGraph->ExecuteGraph的转变已经比较熟悉,并且烂熟于心了,但是它也只是Flink中DAG转变的一部分。

有可能再往下,我问你具体的数据是如何传递,有的数据不只是在Slot内,甚至是Slot间或者跨TM的,脑子就又晕掉了,所以非常有必要对这一部分进行详细的梳理。

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的转化

StreamGraph是啥?

首先StreamGraph的核心是一个StreamNode的拓扑图,StreamNode之间是通过StreamEdge连接。

该拓扑图是通过翻译transformations的链表而来,用户的userFunction最终被flink框架封装成StreamTransformation的调用链,然后再翻译成StreamGraph。普通的Operator会通过图生成器( StreamGraphGenerator)的transform方法来生成对于的StreamNode,而实现分流功能的Select操作以及实现分区的分区选择器则被翻译成虚拟节点并加入到StreamGraph中。

  • 从 StreamExecutionEnvironment.execute 开始执行程序,将 transform 添加到 StreamExecutionEnvironment 的 transformations。
  • 调用 StreamGraphGenerator 的 generateInternal 方法,遍历 transformations 构建 StreamNode 及 StreamEage。
  • 通过 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。

从 source 节点递归寻找嵌到一起的 operator 中,嵌到一起需要满足一定的条件(也就是形成算子链的条件),具体条件介绍如下:

  • 下游节点只有一个输入。
  • 下游节点的操作符不为 null。
  • 上游节点的操作符不为 null。
  • 上下游节点在一个槽位共享组内。
  • 下游节点的连接策略是 ALWAYS。
  • 上游节点的连接策略是 HEAD 或者 ALWAYS。
  • edge 的分区函数是 ForwardPartitioner 的实例。
  • 上下游节点的并行度相等。
  • 可以进行节点连接操作。

为什么要为每个 operator 生成 hash 值?

Flink 任务失败的时候,各个 operator 是能够从 checkpoint 中恢复到失败之前的状态的,恢复的时候是依据 JobVertexID(hash 值)进行状态恢复的。相同的任务在恢复的时候要求 operator 的 hash 值不变,因此能够获取对应的状态。

每个 operator 是怎样生成 hash 值的?

如果用户对节点指定了一个散列值,则基于用户指定的值能够产生一个长度为 16 的字节数组。如果用户没有指定,则根据当前节点所处的位置,产生一个散列值。

考虑的因素主要有三点:

  • 一是在当前 StreamNode 之前已经处理过的节点的个数,作为当前 StreamNode 的 id,添加到 hasher 中;
  • 二是遍历当前 StreamNode 输出的每个 StreamEdge,并判断当前 StreamNode 与这个 StreamEdge 的目标 StreamNode 是否可以进行链接,如果可以,则将目标 StreamNode 的 id 也放入 hasher 中,且这个目标 StreamNode 的 id 与当前 StreamNode 的 id 取相同的值;
  • 三是将上述步骤后产生的字节数据,与当前 StreamNode 的所有输入 StreamNode 对应的字节数据,进行相应的位操作,最终得到的字节数据,就是当前 StreamNode 对应的长度为 16 的字节数组。

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 到物理执行计划。

总结

我感觉这一块知识的梳理有点让我打通任督二脉的意思,因为其实我一直以为DAG图固然很重要,但是仅仅以为他只是在作业调度这一块起一个图纸的作用,就是引导作用,但是仔细通过上述基本是从源码级别的解释来学习发现,DAG图的结点和边还包括了这么多的信息,甚至可以说Flink流处理就是基于DAG结构实现的。

参考资料

《Apache Flink 进阶(六):Flink 作业执行深度解析》

《为什么很多分布式系统都是以DAG(Directed acyclic graph )实现运算的?》

《Flink运行时之作业图》

《flink中级篇-DAG图的剖析》

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值