一个Spark Application分为stage级别和task级别的调度,
task来源于stage,所有本文先从stage提交开始讲解task任务提交。
架构图:
Standalone模式提交运行流程图:
首先写一个WordCount代码(这个代码,为了观察多个suffle操作,我写了两个reducebykey 函数)
源代码:
直接执行代码,查看spark执行程序时,将代码划分stage生成的DAG流程图
可知: WordCount 在stage划分的时候,划分为三个stage
即在代码中如下标识:
讲TaskScheduler ,先从DAGScheduler中提交任务开始吧,其中在stage划分task的时候,涉及到一些优化算法。
org.apache.spark.scheduler.DAGScheduler#handleMapStageSubmitted
这个方法主要有三个部分:
1、创建finalStage
finalStage = getOrCreateShuffleMapStage(dependency, jobId)
2、创建ActiveJob
val job = new ActiveJob(jobId, finalStage, callSite, listener, properties)
3.提交stage
submitStage(finalStage)
直接看第三步 submitStage
这个是提交stage方法。
里面是一个递归方法,举例:
在代码中, 划分为三个stage:
stage0 ---> stage1 ---> stage2
submitStage(stage: Stage) 这个方法先传入的是 finalStage(stage2)
在方法里面循环递归, 分别寻找stage的父stage, 即 stage2 找到 stage1 , stage1找到stage0
stage0 没有父stage 即走 提交方法:
submitMissingTasks(stage: Stage, jobId: Int)
好,接下来,我们看submitMissingTasks
可以看到入参: ShuffleMapStage 0 和 jobId 0
找出当前stage的所有分区中,还没计算完分区的stage
ShuffleMapStage
stage.findMissingPartitions获取需要计算的分区,不同的stage有不同的实现:
ResultStage
计算 分区的最佳位置 : taskIdToLocations
计算最佳位置的核心方法: getPreferredLocsInternal (递归方法)
这个开始传入的RDD:3,
rdd:3找不到最佳位置, 找到rdd:3的父级rdd:2,
rdd2,找不到最佳位置,找到rdd2的父级rdd1
rdd1有最佳位置,直接返回: 具体的机器地址:
广播信息:
为每一个MapStage的分区 创建一个 ShuffleMapTask 或者 ResultTask
将ShuffleMapTask 或者 ResultTask 封装成taskSet,提交Task
在这里执行的是
taskScheduler.submitTasks(new TaskSet(
tasks.toArray, stage.id, stage.latestInfo.attemptNumber, jobId, properties))
接着调用执行的是:
org.apache.spark.scheduler.TaskSchedulerImpl#submitTasks
未完,请看下一篇文章:
Spark2.3.2源码解析: 10. 调度系统 Task任务提交 (二) TaskScheduler
https://blog.csdn.net/zhanglong_4444/article/details/85249376