InfoQ深入浅出Spark(三):Spark调度系统之“权力的游戏”( 六 )


任务提交代码调用流程图仔细观察上面的流程图 , 我们会发现整个分布式任务调度与执行的流程可以分为 3 个阶段 , 也即老大戴格和老二塔斯克之间的交互阶段、老二塔斯克与好基友拜肯德的交互阶段、老三拜肯德与小弟之间的交互阶段 。 咱们来分别看看这 3 个阶段之中都发生了哪些有趣的事情 。
貌合神离 —— 戴格与塔斯克
InfoQ深入浅出Spark(三):Spark调度系统之“权力的游戏”
本文插图
任务提交代码调用流程图 —— DAGScheduler 内部调用
千里之行始于足下 , SparkContext 的 runJob 函数仅仅是向前迈出一小步 , 主要作用是调用 DAGScheduler 的 runJob 函数 , DAGScheduler 内部的函数调用则被囊括到上面的流程图中 。
首先 , runJob 通过调用 submitJob 向 EventProcessLoop 递交 JobSubmitted 事件 , EventProcessLoop 则调用 DAGScheduler 的 handleJobSubmitted 方法以递归的方式创建所有 Stages 。 说到这里 , 各位看官是否觉得似曾相识呢?没错!getOrCreateParentStages 这个环节对应的正是上一篇《内存计算的由来—— DAG》最后 DAGScheduler 创建 Stages 的过程 。
Stages 创建完毕后 , 通过调用 submitStage 来提交 ResultStage 。 值得注意的是 , 在 submitStage 中 , DAGScheduler 会先检查待执行 Stage 所依赖的父 Stages 是否已执行完毕 , 如果没有则递归地提请执行所有未执行的父 Stages 。 对于当下需要执行的 Stage , 调用 submitMissingTasks 提请进行任务调度 。 submitMissingTasks 是这段代码调用的关键 , 主要进行如下 4 项操作:

  • 计算每一个 missing task 的位置偏好(这个时候就需要 BlockManagerMaster 来打配合)
  • 根据 Stage 类型的不同分别创建 ShuffleMapTask 和 ResultTask
  • 创建 TaskSet(注意 , TaskSet 由 DAGScheduler 创建 , 而可调度对象 TaskSetManager 则由 TaskScheduler 创建)
  • 调用 TaskScheduler 的 submitTasks 方法提交刚刚创建的 TaskSet

InfoQ深入浅出Spark(三):Spark调度系统之“权力的游戏”
本文插图
任务提交代码调用流程图 —— TaskScheduler 内部调用
从代码调用的角度 , 我们发现 TaskScheduler 是与外部交互(外连虚线个数)最多的一个模块 , 塔斯克在公司的地位由此可见一斑 。
TaskScheduler 接收到 DAGScheduler 创建的 TaskSet 后 , 第一步就是招聘施工副经理 —— 创建 TaskSetManager , 随即通知秘书把施工副经理安排在合适的位置 , SchedulableBuilder 即调用 addTaskSetManager 方法将刚刚创建的 TaskSetManager 追加到任务队列中 。
在 submitTasks 的最后 , TaskScheduler 调用 SchedulerBackend 的 reviveOffers 方法请求计算资源 , 这一步本质上是塔斯克向好基友拜肯德征集“能干体力活儿”的人力资源 。 分公司的那些小弟们—— ExecutorBackend 每时每刻都在向老板拜肯德汇报麾下可用的人力状况 , 拜老板将这些情况汇总 , 统一反馈给死党塔斯克 。 在第 9 步 , 在拜老板提供了可用的人力资源(WorkerOffer)后 , 塔斯克需要有针对性地“派活儿” , 也即把砌墙分给瓦工、把吊顶分给木工 。
回到代码调用 , resourceOffers 的主要职责是根据 SchedulerBackend 提供的 Worker Offers , 将满足调度条件的任务集以 TaskDescription 序列的形式返还给 SchedulerBackend , 后者将 TaskDescription 分发给对应的 ExecutorBackend 用于执行 —— 这是后话 , 咱们暂且不提 。
resourceOffers 首先将得到的 Worker Offers 的顺序打乱 , 从而避免总是将“活儿”分派给同一个劳力的尴尬局面 , 然后调用调度池(rootPool)的 getSortedTaskSetQueue 方法 , 获取按照 FIFO 规则(FIFOSchedulingAlgorithm)或 FAIR 规则(FairSchedulingAlgorithm)排序后的 TaskSetManager 集合 。 这里的排序规则与 SchedulableBuilder 的构建规则是一一对应的 , 如果是 FIFO 队列 , 则根据 TaskSetManager 的优先级来进行排序;如果是 Fair 队列 , 则同时考虑已调度任务数、weight、minShare 等因素对 TaskSetManager 进行排序 。