Flink 拓扑图源码分析:拓扑图创建与提交过程

本文分析的源码为flink 1.18.0_scala2.12版本。
Flink 分配任务到物理设备上(静态资源分配)过程中,需要将用户代码进行下面的转换:StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图

  • StreamGraph: 是根据用户通过 Stream API 编写的代码生成的最初的图。用来表示程序的拓扑结构。
  • JobGraph: StreamGraph经过优化后生成了 JobGraph,提交给 JobManager 的数据结构。主要的优化为:将多个符合条件的节点链接在一起作为一个节点,这样可以减少数据在节点之间流动所需要的序列化/反序列化的传输消耗。
  • ExecutionGraph: JobManager 根据 JobGraph 生成的分布式执行图,是调度层最核心的数据结构。
  • 物理执行图: JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的“图”,并不是一个具体的数据结构。

在这里插入图片描述
以下是调度的一些步骤的分析。

1. 生成 StreamGraph

StreamGraph 是在 Client 端生成的。

  • Transformation:可查看 flink-streaming-java 模块中 org.apache.flink.streaming.api.transformations 下的类,有各种类型的 Transformation。
  • 算子将用户逻辑封装,并构造出 Transformation,然后将 Transformation 存储到 StreamExecutionEnvironment:
    // 将 Transformation 存储到执行环境中
    getExecutionEnvironment().addOperator(resultTransform);
    
  • 当调用 env.execute() 时,遍历执行环境中的 Transformation 集合,然后使用 StreamGraphGenerator.generate() 创建 StreamGraph。
    StreamGraph streamGraph = getStreamGraph();
    -> final StreamGraph streamGraph = getStreamGraph(transformations);
    	-> getStreamGraphGenerator(transformations).generate();
    		->
    		for (Transformation<?> transformation : transformations) {  
    			transform(transformation);  
    		}
    		// 记录slot共享组及其相应的细粒度资源档案
    		streamGraph.setSlotSharingGroupResource(slotSharingGroupResources);
    		for (StreamNode node : streamGraph.getStreamNodes()) {  
    			if (node.getInEdges().stream().anyMatch(this::shouldDisableUnalignedCheckpointing)) {  
    				for (StreamEdge edge : node.getInEdges()) {  
    					edge.setSupportsUnalignedCheckpoints(false);  
    				}  
    			}  
    		}
    

注:并不是每一个 StreamTransformation 都会转换成 runtime 层中物理操作。有一些只是逻辑概念,比如 union、split/select、partition等。

2. 生成 JobGraph

JobGraph 是在 Client 端生成的。
该部分代码主要在 flink-runtime 模块中的,该过程主要在 org.apache.flink.runtime.jobgraph包中。StreamingJobGraphGenerator.createJobGraph() 中实现。

  • StreamNode 转成 JobVertex,将 one-to-one 且并行的相同的节点合并为一个节点。StreamEdge 转成 JobEdge。会为所有节点生成一个唯一的 hash id,如果节点在多次提交中没有改变(包括并发度、上下游等),那么这个 id 就不会改变,这主要用于故障恢复。

3. 集群接收并处理 JobGraph

这部分实现在 flink-runtime 模块中的 org.apache.flink.runtime.rest.handler.job.JobSubmitHandler.handleRequest() 方法中。在该方法中,会获取 restClient 的文件,获取 JobGraph 和对应的依赖、jar包,然后通过 dispatchergateway 提交 JobGraph。
下面代码负责继续处理 JobGraph。

CompletableFuture<Acknowledge> jobSubmissionFuture =  
        finalizedJobGraphFuture.thenCompose(  
                jobGraph -> gateway.submitJob(jobGraph, timeout));

可进而查看其调用的方法,如下所示。

gateway.submitJob(jobGraph, timeout)
-> internalSubmitJob(jobGraph)
	-> this::persistAndRunJob
		-> runJob(createJobMasterRunner(jobGraph), ExecutionType.SUBMISSION)

在 runJob() 中会创建 JobMaster,然后 JobGraph 在 JobMaster 中会被转化成 ExecutionGraph。

4. 生成 ExecutionGraph

Client 会将 JobGraph 进行提交,然后服务端会接收 JobGraph,创建 JobMaster,并将 JobGraph 转换为 ExecutionGraph。

  • 集群会在创建调度器时,创建 ExecutionGraph。调度器会继承 SchedulerBase 类,在该类的构造函数中通过下面的代码创建 ExecutionGraph。
    this.executionGraph =  
            createAndRestoreExecutionGraph(  
                    completedCheckpointStore,  
                    checkpointsCleaner,  
                    checkpointIdCounter,  
                    initializationTimestamp,  
                    mainThreadExecutor,  
                    jobStatusListener,  
                    vertexParallelismStore);
    
    查看其调用过程如下。
    createAndRestoreExecutionGraph(...)
    -> final ExecutionGraph newExecutionGraph =  
        executionGraphFactory.createAndRestoreExecutionGraph(...)
        -> final ExecutionGraph newExecutionGraph =  
        DefaultExecutionGraphBuilder.buildGraph(...)
    
  • JobManager 会根据 JobGraph 生成对应的 ExecutionGraph。ExecutionGraph 需要根据并行度将每个算子创建 ExecutionGraph,每个 ExecutionGraph 对应一个实例。该功能主要实现在 flink-runtime 模块中的 org.apache.flink.runtime.executiongraph.DefaultExecutionGraphBuilder.buildGraph() 方法中。该方法的部分代码如下:
    // 创建一个执行图 
    final DefaultExecutionGraph executionGraph =  
            new DefaultExecutionGraph(......);  
    // 设置执行图的作业名、节点等信息  
    try {  
        executionGraph.setJsonPlan(JsonPlanGenerator.generatePlan(jobGraph));  
    } catch (Throwable t) {  
        ......
    }  
    ......
    // 创建节点
    for (JobVertex vertex : jobGraph.getVertices()) {  
        try {  
            vertex.initializeOnMaster(  
                    new SimpleInitializeOnMasterContext(  
                            classLoader,  
                            vertexParallelismStore  
                                    .getParallelismInfo(vertex.getID())  
                                    .getParallelism()));  
        } catch (Throwable t) {......}  
    }  
    // topologically sort the job vertices and attach the graph to the existing one  
    List<JobVertex> sortedTopology = jobGraph.getVerticesSortedTopologicallyFromSources();  
    // 生成执行图
    executionGraph.attachJobGraph(sortedTopology, jobManagerJobMetricGroup);
    
  • 33
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值