TaskScheduler
Published on 2017-09-06 09:31 in 暂未分类 with 是奉壹呀

TaskScheduler

    一初始化

    在SparkContext初始化的时候,同时初始化三个对象。DAGScheduler,TaskScheduler,SchedulerBackend。DAGScheduler,前面已经讲到,做stage的划分及每个stage对应的task划分及任务提交,SchedulerBackend用于资源划分。本节讲TaskScheduler。

    复制代码
      private[spark] def schedulerBackend: SchedulerBackend = _schedulerBackend
    
      private[spark] def taskScheduler: TaskScheduler = _taskScheduler
      private[spark] def taskScheduler_=(ts: TaskScheduler): Unit = {
        _taskScheduler = ts
      }
    
      private[spark] def dagScheduler: DAGScheduler = _dagScheduler
      private[spark] def dagScheduler_=(ds: DAGScheduler): Unit = {
        _dagScheduler = ds
      }
    复制代码

    具体到TaskScheduler, 是在createTaskScheduler函数中,使用模式匹配分别对各种情况下创建三个对象。 

    复制代码
     master match {
          case "local" =>case LOCAL_N_REGEX(threads) =>case LOCAL_N_FAILURES_REGEX(threads, maxFailures) =>case SPARK_REGEX(sparkUrl) =>
            val scheduler = new TaskSchedulerImpl(sc)
            val masterUrls = sparkUrl.split(",").map("spark://" + _)
            val backend = new StandaloneSchedulerBackend(scheduler, sc, masterUrls)
            scheduler.initialize(backend)
            (backend, scheduler)
    
          case LOCAL_CLUSTER_REGEX(numSlaves, coresPerSlave, memoryPerSlave) =>
            case masterUrl =>
        }
    复制代码

    在cluster集群模式下,TaskScheduler得到了TaskSchedulerImpl实例,SchedulerBackend得到了StandaloneSchedulerBackend实例。

    2构建调度池

    复制代码
    def initialize(backend: SchedulerBackend) {
        this.backend = backend
        // temporarily set rootPool name to empty
        rootPool = new Pool("", schedulingMode, 0, 0)
        schedulableBuilder = {
          schedulingMode match {
            case SchedulingMode.FIFO =>
              new FIFOSchedulableBuilder(rootPool)
            case SchedulingMode.FAIR =>
              new FairSchedulableBuilder(rootPool, conf)
            case _ =>
              throw new IllegalArgumentException(s"Unsupported spark.scheduler.mode: $schedulingMode")
          }
        }
        schedulableBuilder.buildPools()
      }
    复制代码

    在生成这两个对象后,接下来将backend传入scheduler的初始化方法中进行初始化,TaskSchedulerImpl.initialize方法中主要是根据调度模式初始化调度池。

    spark中的调度模式主要有两种:FIFO和FAIR。默认情况下Spark的调度模式是FIFO(先进先出),谁先提交谁先执行,后面的任务需要等待前面的任务执行。而FAIR(公平调度)模式支持在调度池中为任务进行分组,不同的调度池权重不同,任务可以按照权重来决定执行顺序。

     

     

     

    3启动

    初始化成功,资源调度初始化成功,启动TaskScheduler.

    复制代码
    override def submitTasks(taskSet: TaskSet) {
        val tasks = taskSet.tasks
        logInfo("Adding task set " + taskSet.id + " with " + tasks.length + " tasks")
        this.synchronized {
          // 生成一个TaskSetManager类型对象,
          // task最大重试次数,由参数spark.task.maxFailures设置,默认为4
          val manager = createTaskSetManager(taskSet, maxTaskFailures)
          val stage = taskSet.stageId
          // key为stageId,value为一个HashMap,这个HashMap中的key为stageAttemptId,value为TaskSetManager对象
          val stageTaskSets =
            taskSetsByStageIdAndAttempt.getOrElseUpdate(stage, new HashMap[Int, TaskSetManager])
          stageTaskSets(taskSet.stageAttemptId) = manager
          // 如果当前这个stageId对应的HashMap[Int, TaskSetManager]中存在某个taskSet
          // 使得当前的taskSet和这个taskSet不是同一个,并且当前这个TaskSetManager不是zombie进程
          // 即对于同一个stageId,如果当前这个TaskSetManager不是zombie进程,即其中的tasks需要运行,
          // 并且对当前stageId,有两个不同的taskSet在运行
          // 那么就应该抛出异常,确保同一个Stage在正常运行情况下不能有两个taskSet在运行
          val conflictingTaskSet = stageTaskSets.exists { case (_, ts) =>
            ts.taskSet != taskSet && !ts.isZombie
          }
          if (conflictingTaskSet) {
            throw new IllegalStateException(s"more than one active taskSet for stage $stage:" +
              s" ${stageTaskSets.toSeq.map{_._2.taskSet.id}.mkString(",")}")
          }
          // 根据调度模式生成FIFOSchedulableBuilder或者FairSchedulableBuilder,将当前的TaskSetManager提交到调度池中
          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_MS, STARVATION_TIMEOUT_MS)
          }
          hasReceivedTask = true
        }
        // 向schedulerBackend申请资源
        backend.reviveOffers()
      }
    复制代码

    TaskSetManager

    每个taskset都会创建一个对应的TaskManager来管理其生命周期。通过参数指定如果任务失败后的重试次数。

     

    posted @   是奉壹呀  阅读(329)  评论(0编辑  收藏  举报
    编辑推荐:
    · 如何编写易于单元测试的代码
    · 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
    · .NET Core 中如何实现缓存的预热?
    · 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
    · AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
    阅读排行:
    · 周边上新:园子的第一款马克杯温暖上架
    · Open-Sora 2.0 重磅开源!
    · .NET周刊【3月第1期 2025-03-02】
    · 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
    · [AI/GPT/综述] AI Agent的设计模式综述
    点击右上角即可分享
    微信分享提示