Spark源码解析(五):Task提交流程

Task提交流程

在划分Stage之后,在对Task进行封装成为TaskSet然后提交给TaskScheduler。

Spark带注释源码

对于整个Spark源码分析系列,我将带有注释的Spark源码和分析的文件放在我的GitHub上Spark源码剖析,欢迎大家fork和star

提交流程源码解析

提交TaskSet

查看TaskSchedulerImpl的160行,可以看到submitTasks()方法,主要代码如下:


//TODO 该方法提交TaskSet
  override def submitTasks(taskSet: TaskSet) {
    val tasks = taskSet.tasks
    logInfo("Adding task set " + taskSet.id + " with " + tasks.length + " tasks")
    this.synchronized {
      val manager = createTaskSetManager(taskSet, maxTaskFailures)
      activeTaskSets(taskSet.id) = manager
      schedulableBuilder.addTaskSetManager(manager, manager.taskSet.properties)

      if (!isLocal && !hasReceivedTask) {
        starvationTimer.scheduleAtFixedRate(new TimerTask() {
          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 {
              this.cancel()
            }
          }
        }, STARVATION_TIMEOUT, STARVATION_TIMEOUT)
      }
      hasReceivedTask = true
    }
    //TODO  CoarseGrainedSchedulerBackend类的reviveOffers()
    backend.reviveOffers()

这里主要的的方法是CoarseGrainedSchedulerBackend类的reviveOffers()。

CoarseGrainedSchedulerBackend的reviveOffers()


这里主要是向向DriverActor发送消息
//TODO 向DriverActor发送消息
  override def reviveOffers() {
    driverActor ! ReviveOffers
  }

CoarseGrainedSchedulerBackend中DriverActor的receiveWithLogging()

DriverActor类中的receiveWithLogging()进行模式匹配


//TODO 进行模式匹配,调用makeOffers()向Executor提交Task
case ReviveOffers =>
     makeOffers()

makeOffers()方法向Executor提交Task

Executor运行Task

makeOffers()方法的主要代码如下:


//TODO 调用launchTasks向Executor提交Task
    def makeOffers() {
      launchTasks(scheduler.resourceOffers(executorDataMap.map { case (id, executorData) =>
        new WorkerOffer(id, executorData.executorHost, executorData.freeCores)
      }.toSeq))
    }

这里调用launchTasks(),代码主要的流程是:


 //TODO
    def launchTasks(tasks: Seq[Seq[TaskDescription]]) {
      //TODO Task是一个一个发送给Executor的
      for (task 

Executor执行Task

CoarseGrainedExecutorBackend的模式匹配,主要是DriverActor发送数据给Executor的信息


 //TODO Driver 发送数据给Executor的信息
    case LaunchTask(data) =>
      if (executor == null) {
        logError("Received LaunchTask command but executor was null")
        System.exit(1)
      } else {
        //TODO 拿到序列化器
        val ser = env.closureSerializer.newInstance()
        //TODO 将Task反序列化
        val taskDesc = ser.deserialize[TaskDescription](data.value)
        logInfo("Got assigned task " + taskDesc.taskId)
        //TODO 将反序列化的Task放入线程池执行
        executor.launchTask(this, taskId = taskDesc.taskId, attemptNumber = taskDesc.attemptNumber,
          taskDesc.name, taskDesc.serializedTask)
      }

这里做的工作是拿到序列化器,将Task反序列化,将反序列化的Task放入线程池执行

下面是Executor的launchTask()方法,主要的逻辑是将创建一个TaskRunner对象将Task的信息封装信息然后使用线程池执行


//TODO Executor执行Task
  def launchTask(
      context: ExecutorBackend,
      taskId: Long,
      attemptNumber: Int,
      taskName: String,
      serializedTask: ByteBuffer) {
    //TODO 创建一个TaskRunner对象将Task的信息封装信息
    val tr = new TaskRunner(context, taskId = taskId, attemptNumber = attemptNumber, taskName,
      serializedTask)
    //TODO runningTasks是一个ConcurrentHashMap保证线程安全
    runningTasks.put(taskId, tr)
    //TODO 使用线程池执行
    threadPool.execute(tr)
  }

总结

1.提交Task主要是迭代TaskSet一个一个的取出Task进行序列化之后向Executor发送序列化好的Task

2.Executor执行Task,创建一个TaskRunner对象将Task的信息封装信息然后使用线程池执行

相关系列文章

Spark源码解析(一):Spark执行流程和脚本

Spark源码解析(二):SparkContext流程

Spark源码解析(三):Executor启动流程

Spark源码解析(四):WordCount的Stage划分

微信公众号

有兴趣的同学可以关注一下小编哟!
这里写图片描述

猜你喜欢

转载自blog.csdn.net/oeljeklaus/article/details/80942519