stage提交过程是自下而上切分好stage,自上而下的提交task.
提交TaskSet
这个方法主要是调度task的主体方法,包括stage按照分区进行切分,封装成对应的task,状态位的修改,根据分区task计算最佳的执行ip。 以下是具体的流程。
- 获取当前stage中还没有执行的分区。
- 把stage的状态标记为start
- 根据这些分区信息计算task执行的最佳location
- 序列化stage的rdd, 依赖关系等,并广播给executor
- 封装task的基础信息(监控,执行location, 分区,序列化信息等)
- 调用taskSecheduler.submitTask(); 如果task已经执行完毕了,就调度等待的childStages.
getPreferredLocs
在submitMissingTasks中,有一个比较重要的方法,getPreferredLocs
字面意识就是找到最佳的本地化执行位置。
主要是通过递归的方法去判断RDD是否访问过,没有就返回空,是否缓存, 是否checkpoint,是否RDD的preferredLocations()方法有,有的话就从checkpoint, blockManager里面获取。如果没有就根据依赖往上游rdd回溯。直到找到。
按照我们一般的场景,读取hive表的时候,比如使用的FileScanRDD, 就直接去获取数据存储的位置所在的ip。如果ip在当前的集群中存在,并且资源是空闲的。就可以申请对应的executor的资源。
如果是shuffleRDD, 就会去上游RDD找最佳的location,如果为ExecutorCacheTaskLocation, shuffleRDD就会以当前executor作为最佳的location来使用,如果资源有限,会先等待,或者选择同机架的的location.
TaskLocation
在这里需要说一下几种不同的TaskLocation.
在使用缓存的数据的时候,使用ExecutorCacheTaskLocation,使用hdfs文件的时候使用HostTaskLocation;使用hdfs缓存的时候使用HDFSCacheTaskLocation;
submitTasks
上一步组装出来的taskSet, 就要通过事件在TaskScheduler中进行处理了。
- 首先创建一个TaskSetManager
- 然后把taskSetManager加入到调度的队列中
- 最后预分配资源(先计算消耗的资源)和调度任务
TaskSetManager
TaskSetManager是对task的封装,在实例化的时候对这些task进行了一些初始化。我们直接看addPendingTask。
这个方法主要是把TaskSet中的task根据location进行归类,并且存储到不同的mapping映射中,以供后续调用。因为之前task的location已经计算出来,所以这个地方只是做分类而已(executor, host, 同机架,任意)。
reviveOffers
submitTasks中最重要的就是reviveOffers, 预分配资源和调度。最终调用了DriverEndpoint.makeOffers();
CoarseGrainedSchedulerBackend 是driver端管理控制的主类。所有关于调度控制的都在这个类中,DriverEndpoint就是rpc的调用类
在makeOffsers中,首先拿到所有的的executor的空闲资源。通过这些空闲资源,再通过一些算法,把task和资源进行关联,再进行调度分配。里面包括资源预分配(scheduler.resourceOffsers)和调度task(launcheTasks)
resouceOffsers
预分配资源和调度。
computeValidLocalityLevels
计算本地化级别是根据executor的增减动态变化的,动态计算有一定的性能优化,
根据数据和代码当前的位置,数据本地性等级。从最近到最远的顺序列出如下:
- PROCESS_LOCAL: 数据和代码在同一个JVM中,这是最佳的数据本地性。
- NODE_LOCAL: 数据和代码在相同的节点。比如数据在同一节点的HDFS上,或者在统一节点的Executor上。由于数据要在多个进程间移动,所以比PROCESS_LOCAL稍慢。
- NO_PREF: 数据从哪里访问都一样快,没有数据本地性。
- RACK_LOCAL: 数据和代码在相同的机架。数据位于同一机架上的不同服务器上,因此需要通过网络发送,通常通过单个交换机发送
- ANY: 数据在网络上的其他地方,而不在同一个机架中。
resourceOfferSingleTaskSet
TaskSetManager.resourceOffer
根据真实的运行环境和资源,对task的本地化等级进行重新排列。并且返回最终封装类TaskDescription
launchTasks
这样executor就接收了LaunchTask的任务,具体如何执行,请查看
https://blog.csdn.net/strawhat2416/article/details/120222207