带你看懂Spark2.x源码之Task分配算法

上篇博客中写了关于Stage划分(Stage划分源码),这次把我对Task分配算法的理解给大家分享一下。

点击上篇博客中最后那个代码的TaskScheduler.submitTasks,会发现这里定义了一个方法,但并没有实现

def submitTasks(taskSet: TaskSet): Unit

点击进去,并选择第三个
在这里插入图片描述
接下来继续点击super后面的submitTasks
在这里插入图片描述
查看代码会发现,在这里针对每一个TaskSet都生成了一个TaskSetManager,这里的TaskSetManager就如同一个保姆一样,它会去管理每个Task,并帮助Task去完成之后的Task分配,以及如果Task提交失败的话,它也会将Task重新提交。

override def submitTasks(taskSet: TaskSet) {
    //存到Task数组中
    val tasks = taskSet.tasks
    logInfo("Adding task set " + taskSet.id + " with " + tasks.length + " tasks")
    this.synchronized {
      // 创建TaskSetManager,它会跟踪每个task,如果有失败的task就根据重试次数重新提交
      // 还包括计算数据本地化,构建TaskDescription等
      val manager = createTaskSetManager(taskSet, maxTaskFailures)
      val stage = taskSet.stageId
      //下面一系列操作就是判断Task是否有Task任务进来
      val stageTaskSets =
        taskSetsByStageIdAndAttempt.getOrElseUpdate(stage, new HashMap[Int, TaskSetManager])
      stageTaskSets(taskSet.stageAttemptId) = manager
      val conflictingTaskSet = stageTaskSets.exists { case (_, ts) =>
        ts.taskSet != taskSet && !ts.isZombie
      }
      // TaskSet有冲突情况抛错(也就是Task任务执行失败)
      if (conflictingTaskSet) {
        throw new IllegalStateException(s"more than one active taskSet for stage $stage:" +
          s" ${stageTaskSets.toSeq.map{_._2.taskSet.id}.mkString(",")}")
      }
      // 默认使用的是FIFO调度器(另一种是FAIR公平调度器)
      schedulableBuilder.addTaskSetManager(manager, manager.taskSet.properties)

      if (!isLocal && !hasReceivedTask) {
        starvationTimer.scheduleAtFixedRate(new TimerTask() {
          //在这里会调用Task Run这个方法执行任务
          override def run() {
            // 如果没运行说明集群的资源被占用 还没空闲出来
            if (!hasLaunchedTask) {
              logWarning("Initial job has not accepted any resources; " +
                "check your cluster UI to ensure that workers are registered " +
                "and have sufficient resources")
            } else {
              // 如果提交的Task运行了 就关闭这个Timer线程
              // 释放资源
              this.cancel()
            }
          }
        }, STARVATION_TIMEOUT_MS, STARVATION_TIMEOUT_MS)
      }
      hasReceivedTask = true
    }
    //开始匹配资源,注意这个Backend就是向Master提交Application的,它是SparkContext创建时,就创建出来的CoarseGrainedSchedulerBackend
    backend.reviveOffers()
  }

当我们点击reviveOffers时,会发现它也是个抽象方法,而且它是在SchedulerBackend类中

  def reviveOffers(): Unit

点击SchedulerBackend可以看到CoarseGrainedSchedulerBackend,正好是之前提及到的Backend
在这里插入图片描述
在CoarseGrainedSchedulerBackend按两个shift搜索makeoffers,这里makeOffers方法先过滤掉死亡的executor,然后利用resourceOffers的方法执行任务分配算法,将各个task分配到executor上。在分配好后,再执行launchTasks将分配好的task发送TaskLaunch消息到对应的executor上,由executor执行task。

  private def makeOffers() {
      // Make sure no executor is killed while some task is launching on it
      //确保没有executor节点死亡当有task传输到它上面时
      val taskDescs = CoarseGrainedSchedulerBackend.this.synchronized {
        // Filter out executors under killing
        //过滤掉死亡的executors,剩下的为活跃的executors
        val activeExecutors = executorDataMap.filterKeys(executorIsAlive)
        val workOffers = activeExecutors.map { case (id, execut
  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值