• Spark 资源调度与任务调度的流程(Standalone):

    • 启动集群后, Worker 节点会向 Master 节点汇报资源情况, Master掌握了集群资源状况。

    • 当 Spark 提交一个 Application 后, 根据 RDD 之间的依赖关系将 Application 形成一个 DAG 有向无环图。

    • 任务提交后, Spark 会在任务端创建两个对象: DAGSchedular 和 TaskScheduler

    • DAGSchedular 是任务调度的高层调度器, 是一个对象

    • DAGScheduler 的主要作用是 将 DAG 根据 RDD 之间的宽窄依赖关系划分为一个个的Stage, 然后将 stage 以 TaskSet 的形式 提交给 TaskScheduler

      • TaskScheduler 是任务调度的底层调度器

      • TaskSet 其实就是一个集合, 里面封装的就是一个个task任务, 也就是stage中的并行度 task 任务

        package org.apache.spark.scheduler
        
        import java.util.Properties
        
        /**
        * A set of tasks submitted together to the low-level TaskScheduler,
        * usually representing missing partitions of a particular stage.
        * 一同被提交到低等级的任务调度器的 一组任务集, 通常代表了一个特定的 stage(阶
        * 段) 的 缺失的分区
        */
        private[spark] class TaskSet(
        // 任务数组
        val tasks: Array[Task[_]],
        // 阶段Id
        val stageId: Int,
        // 尝试的阶段Id(也就是下级Stage?)
        val stageAttemptId: Int,
        // 优先级
        val priority: Int,
        // 是个封装过的Hashtable
        val properties: Properties) {
        // 拼接 阶段Id 和 尝试的阶段Id
        val id: String = stageId + "." + stageAttemptId
        // 重写 toString
        override def toString: String = "TaskSet " + id
        }
      • TaskScheduler 会遍历 TaskSet 集合, 拿到每个 task 后将 task发送到 Executor 中执行

      • 其实就是发送到Executor中的线程池ThreadPool去执行

      • 当 task 执行失败时, 则由TaskSchedular负责重试, 将 task重新发送给 Executor 去执行, 默认重试 3 次

          //提交task,最后一行  backend.reviveOffers()  调用的是CoarseGrainedSchedulerBackend对象中的方法
        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)
        // 阶段Id
        val stage = taskSet.stageId // taskSetsByStageIdAndAttempt 是一个 HashMap[Int, TaskSetManager]
        /* getOrElseUpdate(key: A, op: => B): B=
        * 如果 key 已经在这个 map 中, 就返回其对应的value
        * 否则就根据已知的表达式 'op' 计算其对应的value 并将其存储到 map中, 并返回该 value
        */
        val stageTaskSets =
        taskSetsByStageIdAndAttempt.getOrElseUpdate(stage, new HashMap[Int, TaskSetManager])
        // 将阶段任务集合设置为任务管理器
        stageTaskSets(taskSet.stageAttemptId) = manager
        // 获取冲突的任务集 如果 stageTaskSets 的任务集 不是传入的任务集 并且stageTaskSets的任务集不是僵尸进程 那么它就是冲突的任务集
        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(",")}")
        }
        // 通过可调度的构造器创建一个任务集管理器
        schedulableBuilder.addTaskSetManager(manager, manager.taskSet.properties)
        // 如故不是本地提交 或者 没有接收到任务
        if (!isLocal && !hasReceivedTask) {
        // 通过饥饿的计时器 来 根据 固定的比例进行调度
        // scheduleAtFIxedRate 方法的三个参数: 时间任务, 延迟时间, 周期 如果延迟时间或周期值为父会抛出异常
        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()
        }
        }
        // 默认的饥饿超时临界值: 15s
        }, STARVATION_TIMEOUT_MS, STARVATION_TIMEOUT_MS)
        }
        hasReceivedTask = true
        }
        // 调用 CoarseGrainedSchedulerBackend对象中的方法
        backend.reviveOffers()
        }
      • 如果重试 3 次 依然失败, 那么这个 task 所在的 stage 就失败了

      • 如果 stage 失败了则由 DAGScheduler 来负责重试, 重新发送 TaskSet 到 TaskScheduler, Stage 默认重试 4 次。

      • 如果重试 4 次 以后依然失败, 那么 该 job 就失败了。

      • 一个 job 失败了, Application 就失败了。

    • TaskScheduler 不仅能重试失败的 task, 还会重试 straggling(直译是挣扎的, 这边可以意译为缓慢的) task(执行速度比其他task慢太多的task)

      /**
      * TaskScheduler 启动
      */
      override def start() {
      //StandaloneSchedulerBackend 启动
      backend.start() if (!isLocal && conf.getBoolean("spark.speculation", false)) {
      logInfo("Starting speculative execution thread")
      // 启动定期执行推测任务线程
      speculationScheduler.scheduleWithFixedDelay(new Runnable {
      override def run(): Unit = Utils.tryOrStopSparkContext(sc) {
      // 检查所有活跃的jon中是否有可推测的任务
      checkSpeculatableTasks()
      }
      }, SPECULATION_INTERVAL_MS, SPECULATION_INTERVAL_MS, TimeUnit.MILLISECONDS)
      }
      }
      // Check for speculatable tasks in all our active jobs.
      // 检查是否有可推测的任务
      def checkSpeculatableTasks() {
      // 是否应该重新激活
      var shouldRevive = false
      // 加同步锁
      synchronized {
      // 检查是否有可推测的任务(传入执行推测所需的最小时间)
      shouldRevive = rootPool.checkSpeculatableTasks(MIN_TIME_TO_SPECULATION)
      }
      // 如果需要重新激活
      if (shouldRevive) {
      // 就尝试运行推测任务
      backend.reviveOffers()
      }
      }
    • Spark 推测执行机制:

      • 如果有运行缓慢的 task, 那么 TaskScheduler 会启动一个新的 task 来与该运行缓慢的 task 执行相同的处理逻辑。

      • 两个 task 哪个先执行完, 就以哪个 task 的执行结果为准。

      • 在 Spark 中推测执行默认是关闭的。

      • 推测执行可以通过 spark.speculation 属性来配置

          /**
        * Return a speculative task for a given executor if any are available
        * 如果有卡壳的进程,就向已知的executor进程返回一个推测任务
        * The task should not have an attempt running on this host, in case
        * the host is slow.
        * 该任务不应有任何尝试任务在该主机上运行, 以防止该主机是有延迟的
        * In addition, the task should meet the given locality constraint.
        * 此外, 该任务需要满足已知的本地约束
        */
        // Labeled as protected to allow tests to override providing speculative tasks if necessary
        // 标注为 protected 以允许测试 来重写 提供的推测任务(如果需要的话)
        protected def dequeueSpeculativeTask(execId: String, host: String, locality: TaskLocality.Value)
        : Option[(Int, TaskLocality.Value)] =
        {
        // 从推测式执行任务列表中移除已经成功完成的task
        speculatableTasks.retain(index => !successful(index)) // Remove finished tasks from set // 1.判断 task 是否可以在该executor对应的Host上执行, 判断条件为:
        // 2.没有taskAttempt在该Host上运行
        // 3. 该 executor 没有在 task 的黑名单中(task 在该executor上失败过, 并且仍在‘黑暗’时间中)
        def canRunOnHost(index: Int): Boolean = {
        !hasAttemptOnHost(index, host) &&
        !isTaskBlacklistedOnExecOrNode(index, execId, host)
        }
        // 判断推测执行任务集合是否为空
        if (!speculatableTasks.isEmpty) {
        // Check for process-local tasks;
        // 检查 本地进程任务
        // note that tasks can be process-local on multiple nodes when we replicate cached blocks, as in Spark Streaming
        // 需要注意的是: 当我们备份缓存块时, 任务可以以本地进程 或者 多节点的形式运行 (就像spark流那样)
        for (index <- speculatableTasks if canRunOnHost(index)) {
        val prefs = tasks(index).preferredLocations
        val executors = prefs.flatMap(_ match {
        case e: ExecutorCacheTaskLocation => Some(e.executorId)
        case _ => None
        });
        // 如果 executor 进程包含该任务Id
        if (executors.contains(execId)) {
        // 就不推测该任务
        speculatableTasks -= index
        // 返回某个本地进程
        return Some((index, TaskLocality.PROCESS_LOCAL))
        }
        } // Check for node-local tasks 检查本地节点的任务
        if (TaskLocality.isAllowed(locality, TaskLocality.NODE_LOCAL)) {
        for (index <- speculatableTasks if canRunOnHost(index)) {
        val locations = tasks(index).preferredLocations.map(_.host)
        if (locations.contains(host)) {
        speculatableTasks -= index
        return Some((index, TaskLocality.NODE_LOCAL))
        }
        }
        } // Check for no-preference tasks 检查非优先级的任务
        if (TaskLocality.isAllowed(locality, TaskLocality.NO_PREF)) {
        // 遍历 speculatableTasks, 如果有任务能够在主机上运行
        for (index <- speculatableTasks if canRunOnHost(index)) {
        // 获取该task的优先级位置
        val locations = tasks(index).preferredLocations
        if (locations.size == 0) {
        speculatableTasks -= index
        return Some((index, TaskLocality.PROCESS_LOCAL))
        }
        }
        } // Check for rack-local tasks 监察本地构建的任务
        if (TaskLocality.isAllowed(locality, TaskLocality.RACK_LOCAL)) {
        for (rack <- sched.getRackForHost(host)) {
        for (index <- speculatableTasks if canRunOnHost(index)) {
        val racks = tasks(index).preferredLocations.map(_.host).flatMap(sched.getRackForHost)
        if (racks.contains(rack)) {
        speculatableTasks -= index
        return Some((index, TaskLocality.RACK_LOCAL))
        }
        }
        }
        } // Check for non-local tasks 检查非本地性的任务
        if (TaskLocality.isAllowed(locality, TaskLocality.ANY)) {
        for (index <- speculatableTasks if canRunOnHost(index)) {
        speculatableTasks -= index
        return Some((index, TaskLocality.ANY))
        }
        }
        } None
        }
        • 需要注意的是:

          • 对于 ETL(Extract Transformation Load) 类型的需要导入数据库的业务需要关闭推测执行机制, 否则会有重复的数据导入数据库。
          • 如果遇到数据倾斜的情况, 开启推测执行则有可能导致一直会有 task 重新启动处理相同的逻辑, 任务可能一直处于处理不完的状态。
  • 粗粒度资源申请 和 细粒度资源申请

    • 粗粒度资源申请(Spark)

      • 在 Application 执行之前, 将所有的资源申请完毕, 当资源申请成功后, 才会进行任务的调度, 当所有的 task 执行完成后才会释放这部分资源

      • 优点

        • 在 Application 执行之前, 所有的资源都申请完毕, 每一个 task 直接使用资源就可以了, 不需要 task 在执行前自己去申请资源。
        • task 执行快了 => stage 执行就快了 => job 执行就快了 => application 执行就快了
      • 缺点

        • 直到最后一个 task 执行完成才会释放资源, 集群的资源无法充分利用。(俗称: 占着M坑不拉S)
    • 细粒度资源申请(MR)

      • Application 执行之前不需要先去申请资源, 而是直接执行, 让 job 中的每一个 task 在执行前自己去申请资源, task执行完成就释放资源。

      • 优点

        • 集群的资源可以充分利用
      • 缺点

        • task自己去申请资源,task启动变慢,Application的运行就响应的变慢了。

Spark 资源调度 与 任务调度的更多相关文章

  1. 【Spark篇】---Spark资源调度和任务调度

    一.前述 Spark的资源调度是个很重要的模块,只要搞懂原理,才能具体明白Spark是怎么执行的,所以尤其重要. 自愿申请的话,本文分粗粒度和细粒度模式分别介绍. 二.具体 Spark资源调度流程图: ...

  2. 【Spark-core学习之六】 Spark资源调度和任务调度

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...

  3. Spark 资源调度及任务调度

    1.  资源分配 通过SparkSubmit进行提交应用后,首先会创建Client将应用程序(字节码文件.class)包装成Driver,并将其注册到Master.Master收到Client的注册请 ...

  4. Spark资源调度及任务调度

    1.  资源分配 通过SparkSubmit进行提交应用后,首先会创建Client将应用程序(字节码文件.class)包装成Driver,并将其注册到Master.Master收到Client的注册请 ...

  5. Spark资源调度和任务调度

    一.资源调度&任务调度 1.启动集群后,Worker节点会周期性的[心跳]向Master节点汇报资源情况,Master掌握集群资源情况. 2.当Spark提交一个Application后,根据 ...

  6. Spark Core_资源调度与任务调度详述

    转载请标明出处http://www.cnblogs.com/haozhengfei/p/0593214ae0a5395d1411395169eaabfa.html Spark Core_资源调度与任务 ...

  7. Spark Core 资源调度与任务调度(standalone client 流程描述)

    Spark Core 资源调度与任务调度(standalone client 流程描述) Spark集群启动:      集群启动后,Worker会向Master汇报资源情况(实际上将Worker的资 ...

  8. spark 图文详解:资源调度和任务调度

    讲说spark的资源调度和任务调度,基本的spark术语,这里不再多说,懂的人都懂了... 按照数字顺序阅读,逐渐深入理解:以下所有截图均为个人上传,不知道为什么总是显示别人的QQ,好尴尬,无所谓啦, ...

  9. [Spark内核] 第31课:Spark资源调度分配内幕天机彻底解密:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结

    本課主題 Master 资源调度的源码鉴赏 [引言部份:你希望读者看完这篇博客后有那些启发.学到什么样的知识点] 更新中...... 资源调度管理 任务调度与资源是通过 DAGScheduler.Ta ...

随机推荐

  1. 题解 AT1219 【歴史の研究】

    莫队 简单分析:题面含有IOI(惊),可知此题是IOI(数字三角形)难度(逃). 思路:回滚莫队 当然很多人都是抱着学回滚莫队的目标来看这道题的,所以这里介绍一下回滚莫队. 1.按莫队的思路讲询问排序 ...

  2. python面向对象之练习题2

    练习题 需求: 士兵 可以 花钱买一个AK47 士兵 可以 用开开火 士兵 可以 买弹夹 士兵 可以 上子弹 士兵 可以 给 枪 添加子弹 枪 需要弹夹和有子弹的情况下,借助士兵扣动扳机 才能开火 枪 ...

  3. Vue 项目开发

    目录 Vue 项目开发 项目目录结构解析 入口文件 main.js (项目入口) 根组件 app.vue index.html 文件入口 router 路由 components 子组件 项目初始化 ...

  4. SAP BO WebI 如何连接webi server folder下面的EXCEL文件作为数据源

    昨天做Webi Report,需要连接一个在Webi Server Folder下面的EXCEL文件作为数据源,然后再去生成相应的报表,找了半天才找到可以连接Webi Server Folder的EX ...

  5. SpringCloud实战——(3)通过RESTful方式调用模块的方法

    在项目中创建一个类,编写如下内容: package com.f*iservice.controller; import org.springframework.web.bind.annotation. ...

  6. docker学习笔记-06:自定义DockerFile生成镜像

    一.自定义centos的DockerFile 1.从阿里源里拉的centos镜像新建的容器实例中,没有vim编辑器和ifconfig命令,所以自定义centos的DockerFile,创建自己想要的镜 ...

  7. Mixin类的实现

    python类的多重继承由于C3算法的原因导致实现时需要提前规划先后顺序才能正常使用. 这会让人在python中使用多重继承时感到十分的麻烦. 而Mixin类则为我们带来了自由的多重继承和插拔式的舒适 ...

  8. 攻防世界web新手区(3)

    xff_referer:http://111.198.29.45:43071 打开网址,显示出这个页面: X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP, ...

  9. VM ubuntu18.04.01虚拟机没办法联网

    sudo service network-manager stop sudo rm /var/lib/NetworkManager/NetworkManager.state sudo service ...

  10. mac java 装机清单

    1. JDK8 2. Eclipse IDE for Enterprise Java Developers 3. maven 4. Postman 5. VS Code 6. finalshell ( ...