一、概述

TaskSchedulerImpl 对 Task 的调度依赖于调度池 Pool,所有需要被调度的 TaskSet 都被置于调度池中。调度池 Pool 通过调度算法对每个 TaskSet 进行调度,并将被调度的 TaskSet 交给 TaskSchedulerImpl 进行资源调度。

调度池内部有一个根调度队列,根调度队列中包含了多个子调度池。子调度池自身的调度队列中还可以包含其他的调度池或者TaskSetManager,整个调度池是一个多层次的调度队列。

二、调度算法

调度池对 TaskSet 的调度取决于调度算法

2.1. FIFO 调度算法 FIFOSchedulingAlgorithm

如果是采用 FIFO 调度策略,则直接简单地将 TaskSetManager 按照先来先到的方式入队,出队时直接拿出最先进队的 TaskSetManager

1
2
3
4
5
6
7
8
9
10
11
12
13
private[spark] class FIFOSchedulingAlgorithm extends SchedulingAlgorithm {
override def comparator(s1: Schedulable, s2: Schedulable): Boolean = {
val priority1 = s1.priority // jobId
val priority2 = s2.priority
var res = math.signum(priority1 - priority2)
if (res == 0) {
val stageId1 = s1.stageId
val stageId2 = s2.stageId
res = math.signum(stageId1 - stageId2)
}
res < 0
}
}
  • 比较 s1和 s2 所属的 JobId,值越小,优先级越高
  • 如果两个 JobId 的优先级相同, 则对 s1,s2所属的 StageId 进行比较,值越小,优先级越高

2.2. Fair 调度算法 FairSchedulingAlgorithm

FAIR 模式中有一个 Root Pool 和多个子 Pool,各个子 Pool 中 存储着所有待分配的 TaskSetManager

可以通过在 Properties 中指定 spark.scheduler.pool 属性,指定某个调度池作为 TaskSetManager 的父调度池,如果根调度池不存在此属性值对应的调度池,会创建以此属性值为名称的调度池作为 TaskSetManager 的父调度池,并将此调度池作为根调度池的子调度池。

在 FAIR 模式中,使用相同的排序算法先对 子Pool 进行排序,再对子 Pool 里面的 TaskSetManager 进行排序

因为 Pool 和 TaskSetManager 都继承了 Schedulable 特质。

每个要排序的对象包含三个属性 : runningTasks 值[正在运行的 Task 数]、 minShare 值、 weight 值,比较时会综合考量三个属性值。

注意,minShare 、weight 的值均在公平调度配置文件 fairscheduler.xml 中被指定, 调度池在构建阶段会读取此文件的相关配置。

1
2
3
4
5
6
7
8
9
10
11
12
<allocations>
<pool name="production">
<schedulingMode>FAIR</schedulingMode>
<weight>1</weight>
<minShare>2</minShare>
</pool>
<pool name="test">
<schedulingMode>FIFO</schedulingMode>
<weight>2</weight>
<minShare>3</minShare>
</pool>
</allocations>
  • runningTasks 比 minShare 小的先执行

    如果 A 对象的 runningTasks 大于它的 minShare,B 对象的 runningTasks 小于它的 minShare,那么 B 排在 A 前面

  • minShare 使用率低的先执行

    如果A,B 对象的 runningTasks 都小于它的 minShare ,那么就比较 runningTasks 和 minShare 的比值 [minShare使用率]谁小谁排前面

  • 权重使用率低的先执行

    如果A、B 对象 的 runningTasks 都大于它们的 minShare ,那么就比较 runningTasks 与 weight 的比值(权重使用率),谁小谁排前面。

    整体上来说就是通过 minShare 和 weight 这两个参数控制比较过程,可以做到

    让 minShare 使用率和权重使用率少(实际运行 task 比例较少)的先运行。

  • 如果上述比较均相等,则比较名字

从调度队列中拿到 TaskSetManager 后,由于 TaskSetManager 封装了一个 Stage 的所有 Task, 并负责管理调度这些 Task,接下来 TaskSetManager 按照一定的规则逐个取出 Task 给 TaskScheduler,TaskScheduler 提交给 SchedulerBackend 去发到 Executor 执行。

三、Pool 实现

TaskScheduler 对任务的调度是借助于调度池实现的,Pool 是对 Task 集合进行调度的调度池。调度池内部有一个根调度队列,根调度队列中包含了多个子调度池。子调度池自身的调度队列中还可以包含其他的调度池或者 TaskSetManager,整个调度池是一个多层次的调度队列。

https://weread.qq.com/web/reader/0c832fb05e12e40c8ca6190k14b3246024514bfa6bb1534

3.1. 结构

3.2. 调度池构建器 SchedulableBuilder

特质 SchedulableBuilder 定义了调度池构建器的行为规范