Flink内核源码
- 1、掌握Flink应用程序抽象
- 2、掌握Flink核心组件整体架构抽象
- 3、掌握Flink Job三种运行模式
- 4、理解Flink RPC网络通信框架Akka详解
- 5、理解TaskManager为例子,分析Flink封装Akka Actor的方法和整个调用流程
- 6、理解Flink高可用服务HighAvailabilityServices
- 7、理解Flink选举服务LeaderElectionService和监听LeaderRetrievalService机制
- 8、理解Flink文件/大对象服务BlobService
- 9、理解Flink心跳机制HeartbeatServices
总的来说,先了解清楚Flink的一些重要工作和通信机制,然后再去剖析一个Flink Job 到底是如何执行的,Flink的 Cluster到底是如何管理和分配slot资源的等等,就比较容易了。
1、Flink应用程序抽象
Flink 的整体架构设计
概念解释:
-
Dataflow Graph:是一个逻辑上的概念,表示这个应用程序的执行图,在客户端中会生成两张图:
StreamGraph+JobGraph:-
StreamGraph中有两个非常重要的概念:StreamNode(operation算子) + StreamEdge(连续两个算子的边)
-
JobGraph
javafinal JobGraph jobGraph = PipelineExecutorUtils.getJobGraph(pipeline, configuration);
-
-
client 是一个Http方式的Restful Client,负责将JobGraph递交到JobMaster
-
JobManager接收到JobGraph后,会做一些非常重要的操作,启动 jobMaster,jobMaster负责该job的执行,也就是一个jobMaster对应一个JobGraph,在构造JobMaster时候,会把JobGraph构造成ExecutionGraph
- Execution = ExecutionVertex(顶点) (里面有一个抽象表示一个Task的一切信息)
-
JobMaster接下来会向ResourceManager (并不是Yarn的ResourceManager而是JobManager组件) 申请资源,申请slot资源,部署task启动执行
-
当所有的task都部署到taskManager里面以后,启动完成了,上下游的task都建立了连接,最终组成PhysicalGraph (物理执行图)
Flink的一个Job,最终归根结底,还是构建一个高效率的能用于分布式并行执行的DAG执行图。
Flink的执行图可以分为四层:StreamGraph ===> JobGraph ===> ExecutionGraph ===> PhysicalGraph (物理执行图)
- StreamGraph:是根据用户通过Stream API 编写的代码生成的最初的图。用来表示程序的拓扑结构。ds.xx1.xx2.xx3.xx4(),ds1.join(ds2)
- JobGraph:StreamGraph经过优化后生成了 JobGraph,提交给 JobManager的数据结构。主要的优化为:将多个符合条件的节点 chain在一起作为一个节点,这样可以减少数据在节点之间流动所需要的序列化反序列化传输消耗。
- ExecutionGraph:JobManager根据JobGraph生成ExecutionGraph。ExecutionGraph 是JobGraph的并行化版本,是调度层最核心的数据结构。
- PhysicalGraph (物理执行图):JobManager 根据ExecutionGraph 对Job 进行调度后,在各个TaskManager上部署Task后形成的图,并不是一个具体的数据结构。
Flink的四层图模型:
上面这张图清晰的给出了Flink各个图的工作原理和转换过程。其中最后一个物理执行图并非Flink的数据结构,而是程序开始执行后,各个Task分布在不同的节点上,所形成的物理上的关系表示:
- 从JobGraph的图里可以看到,数据从上一个operator(JobVertex)流到下一个operator(JobVertex)的过程中,上游作为生产者提供了IntermediateDataSet,而下游作为消费者需要JobEdge。事实上,JobEdge是一个通信管道,连接了上游生产的dataset和下游的JobVertex节点。
- 在JobGraph转换到ExecutionGraph的过程中,主要发生了以下转变:
- 加入了并行度的概念,成为真正可调度的图结构
- 生成了与JobVertex对应的ExecutionJobVertex,ExecutionVertex,与IntermediateDataSet 对应的IntermediateResult 和 IntermediateResultPartition等,并行将通过这些类实现
- ExecutionGraph 已经可以用于调度任务,我们可以看到,Flink根据该图生成了------对应的Task,每个Task对应一个ExecutionGraph的Execution。Task用InputGate、InputChannel和ResultPartition对应上面图中的 ExecutionEdge 和 IntermediateResult。
那么,设计中为什么要设计这四层执行逻辑呢?它的意义是什么?
1、StreamGraph 是对用户逻辑的映射
2、JobGraph 在StreamGraph 基础上进行了一些优化,比如把一部分操作串成 chain 以提高效率
3、ExecutionGraph 是为了调度存在的,加入了并行处理的概念
4、物理执行结构:真正执行的是 Task 及其相关结构
总结:Flink的四层图结构:
1、
StreamGraph
就是通过用户编写程序时指定的算子进行逻辑拼接的简单说:就是进行算子拼接
2、
JobGraph
其实就是在 StreamGraph 的基础上做了一定的优化,然后生成的逻辑执行图简单说:就是把能优化的Operator拼接在一起,放到一个Task中执行的算子的整合和
优化chain在一起形成OperatorChain,类似于Spark Stage切分
3、
ExecutionGraph
再把JobGraph进行并行化生成ExecutionGraph简单说:其实ExecutionGraph 就是JobGraph的并行化版本
4、
物理执行图
其实是ExecutionGraph 调度运行之后形成的分布,当一个Flink Stream Job中的所有Task 都被调度执行起来了之后的状态
简单说:就是最终运行状态图
两个重要的转化
1、StreamGraph 转变成 JobGraph:帮我们把上下游两个相邻算子如果能chain到一起,则chain到一起做优化
2、JobGraph转变成ExecutionGraph:chain到一起的多个Operator就会组成一个OperatorChain,当OperatorChain 执行的时候,到底要执行多少个Task,则就需要把 DAG 进行并行化变成实实在在的 Task 来调度
StreamGraph
StreamGraph:根据用户通过Stream API 编写的代码生成的最初的图。Flink把每一个算子 transform 成一个对流的转换(比如 SingleOutputStreamOperator,它就是一个 DataStream 的子类),并且注册到执行环境中,用于生成 StreamGraph。
它包含的主要抽象概念有:
1、StreamNode:用来代表 operator 的类,并具有所有相关的属性,如并发度、入边和出边等。
2、StreamEdge:表示连接两个 StreamNode的边
JobGraph
JobGraph:StreamGraph 经过优化后生成了 JobGraph,提交给 JobManager 的数据结构它包含的主要抽象概念有:
1、JobVertex:经过优化后符合条件的多个 StreamNode 可能会chain 在一起生成一个 JobVertex,即一个JobVertex 包含一个或多个 operator,JobVertex 的输入是 JobEdge,输出是 IntermediateDataSet。
2、IntermediateDataSet:表示JobVertex 的输出,即经过 operator 处理产生的数据集,producer 是JobVertex,consumer 是 JobEdge。
3、JobEdge:代表了job graph 中的一条数据传输通道。Source 是 IntermediateDataSet,targe 是 JobVertex。即数据通过 JobEdge 由IntermediateDataSet 传递给目标 JobVertex。
ExecutionGraph
ExecutionGraph:JobManager(JobMaster) 根据 JobGraph 生成 ExecutionGraph。ExecutionGraph 是JobGraph 的并行化版本,是调度层最核心的数据结构。
它包含的主要抽象概念有:
1、ExecutionJobVertex:和JobGraph中的JobVertex一一对应,每一个ExecutionJobVertex都有和并发度一样多的 ExecutionVertex。
2、ExecutionVertex:表示ExecutionJobVertex 的其中一个并发子任务,输入是ExecutionEdge,输出的是IntermediateResultPartition。
3、IntermediateResult:和 JobGraph 中的 IntermediateDataSet一一对应。一个 IntermediateResult包含多个 IntermediateResultPartition,其个数等于该 operator 的并发度。
4、IntermediateResultPartition:表示ExecutionVertex的一个输出分区,producer是ExecutionVertex,consumer是若干个ExecutionEdge。
5、ExecutionEdge:表示ExecutionVertex的输入,source 是IntermediateResultPartition,targe 是 ExecutionVertex。source 和 target 都只能是一个 EdgeManager
6、Execution:是执行一个 ExecutionVertex 的一次尝试。当发生故障或者数据需要重算的情况下 ExecutionVertex 可能会有多个 ExecutionAttemptID。一个 Execution 通过 ExecutionAttemptID 来唯一表示。JM 和 TM 之间关于 task 的部署和 task status 的更新都是通过 ExecutionAttemptID 来确定消息接受者。
物理执行图
物理执行图:JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的"图
",并不是一个具体的数据结构。
它包含的主要抽象概念有:
1、Task:Execution 被调度后在分配的 TaskManager 中启动对应的 Task。Task包裹了具有用户执行逻辑的 operator。
2、ResultPartition:代表由一个 Task 的生成的数据,和 ExecutionGraph 中的IntermediateResultPartition 一一对应。
3、ResultSubPartition:是 ResultPartition 的一个子分区,每个 ResultPartition 包含多个 ResultSubPartition,其数据要由下游消费 Task 数和 DistributionPattern 来决定。
4、InputGate:代表 Task 的输入封装,和 JobGraph 中 JobEdge 一一对应,每个 InputGate 消费了一个或者多个的 ResultPartition。
5、InputChannel:每个 InputGate 会包含一个以上的 InputChannel,和 ExecutionGraph 中的 ExecutionEdge 一一对应,也和 ResultSubpartition一对一的相连,即一个 InputChannel 接收一个 ResultSubpartition 的输出。
2、Flink 核心组件整体架构抽象
JobManger 作业管理器
注意:
- JobManager 是控制一个应用程序执行的主进程,相当于集群的Master节点,且整个集群有且只有一个活跃的JobManager
- JobManager 负责整个Flink集群任务的调度以及资源的管理。
- 默认情况下,每个Flink 集群只有一个JobManager 实例。可能会产生单点故障(SPOF),可配置高可用。
说明:
- jobManager 作业管理器会先接收到要执行的应用程序
- 包括:作业图(JobGraph)、逻辑数据流图(logicaldataflow graph)和打包了所有的类、库和其他资源的JAR包。
- JobManager 作业管理器会向资源管理器 (ResourceManager)请求执行任务必要的资源
- 也就是任务管理器(TaskManager) 上的插槽(slot)
- 一旦获取到足够的资源,就会将任务图分发到真正运行它们的TaskManager上。
- 在运行过程中,作业管理器会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调
描述:
- JobManger 负责整个 Flink 集群人物的调度以及资源的管理。
- JobManger 从客户端中获取提交的应用,然后根据集群中TaskManger 上 TaskSlot 的使用情况,为提交的应用分配相应的TaskSlot 资源,并命令TaskManager 启动从客户端中获取的应用。
- 当任务完成后,Flink 会将任务执行的信息反馈给客户端,并且释放掉 TaskManager 中的资源以供下一次提交任务使用。
ResourceManager 资源管理器
注意:
ResourceManager
主要负责任务管理器(TaskManager)的插槽(Slot)
,TaskManager插槽是Flink中定义的处理资源单元
- Flink为不同的环境和资源管理工具
提供了
不同的资源管理器比如Yarn,K8s,以及 Standalone 部署。
作用:
- 当JobManager 作业管理器申请插槽资源时,ResourceManager 会将空闲插槽的 TaskManager分配给作业管理器。
- 如果ResourceManager没有足够的插槽来满足作业管理器的请求,他还可以向资源提供平台发起会话,以提供启动 TaskManager进程的容器。
- ResourceManager 还负责终止空闲的TaskManager,释放计算资源
描述:
管理资源
- 为不同环境
提供
各种的资源管理器分配
空闲插槽终止
空闲TaskManager,释放资源
TaskManager 任务管理器
注意:
- TaskManager 是Flink中的工作进程,相当于整个集群的Slave 节点,Flink集群可存在
多个
TaskManager 运行。 - TaskManager 负责具体的
任务执行
和对应任务在每个节点上的资源申请和管理
。
描述:
- 通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。
- 插槽的数量限制了TaskManager能够执行的任务数量。
- 启动之后,TaskManager会向资源管理器注册它的插槽。
- 收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给作业管理器调用,作业管理器就可以向插槽分配任务。
- 在执行过程中,一个TaskManager可以跟其他运行同一应用程序的TaskManager交换数据,同时TaskManager 之间的数据交互都是通过数据流的方式进行的。
Dispatcher 分发器
说明:
- Dispatcher 分发器可以跨作业运行,它为应用提交提供了REST接口。
- 当一个应用被提交执行时,分发器就会启动并将应用移交给一个作业管理器。
- 由于是REST接口,所以Dispatcher可以作为集群的一个HTTP接入点,这样就能够不受防火墙阻挡。
- Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行的信息。
- Dispatcher在架构中可能并不是必须的,这取决于应用提交运行的方式。
3、Flink Job 三种运行模式
在一些应用场景中,对于集群资源分配和占用的方式,可能会有特定的需求。Flink为各种场景提供了不同的部署模式,主要有以下三种
- 会话模式(Session Mode)
- 单作业模式(Per-Job Mode)
- 应用模式(Application Mode)
它们的区别主要在于:集群的生命周期和资源分配方式不同、以及应用程序的 main() 方法到底在哪执行。客户端(Client)还是 JobManager。
这里我们重点探讨 Flink On Yarn。
Flink RPC 网络通信框架Akka
以往,我们接触过非常多的大数据技术栈相关的框架,用的比较多的大数据相关组件,常用的RPC实现技术如下:
技术组件 | RPC实现 |
---|---|
Hadoop | NIO + Protobuf (Protobuf即Protocol Buffers,是Google公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的, 高效的用于序列化数据的协议) |
Hbase | Hbase2.x以前:NIO + ProtoBuf,Hbase2.x会议后:Netty |
ZooKeeper | BIO(Blocking I/O,同步阻塞I/O模式) + NIO (New I/O,同步非阻塞的I/O模型) + Netty |
Spark | Spark-2.x 以前 基于 Akka Actor,Spark2.x往后基于 Netty RpcEndpoint |
Flink | Akka(组件中间)+ Netty (operator) |
Kafka | NIO |
在Flink中主从节点之间的通信组件,即:akka,可以通过Flink web ui进行确认
[外链图片转存失败,源站可能有防盗在这里插入!链机制,建描述]议将图片上https://传(im-log.animg.cn/95abeydD1907ef2e234a8895036959ea70(aa0.png:tps://img-blog.csdnimg.cn/951907ef2e234a889e553506ea909aa0.png)]
为什么Flink使用了两套通信框架呢?这是因为Flink节点与节点之间,组件与组件之间通信采用的是Akka,但是数据交换,比如算子与算子之间的数据交换采用的是Netty,比如Flink中有JobManager,还有TaskManager从节点,而JobManager主节点里面有一些组件,比如JobMaster,Dispatcher等,组件与组件之间通信采用的是Akka,而Netty是算子与算子之间,比如Map算子后面跟着Filter,Filter后面跟着reducekeyby等操作这些算子之间采用的是Netty来通信的。
Fink 内部节点之间的通信是用Akka,比如JobManager 和 TaskManager之间的通信,而operator之间的数据传输是采用的Netty
Flink通过Akka
进行的分布式通信的实现,有远程过程调用都实现为异步消息,这主要影响组件:JobManager,TaskManager 和JobClient.
RPC框架是Flink任务运行的基础,Flink整个RPC框架基于Akka实现,并对Akka中的ActorSystem, Actor 进行了封装和使用,Flink整个通信框架的组件主要由 RpcEndpoint,RpcService,RpcServer,AkkaInvocationHandler,AkkaRpcActor等构成。