spark2原理分析-Task调度对象Pool原理分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zg_hover/article/details/84670461

概述

本文分析Task调度器的Pool调度对象的实现原理。

通过文章spark2原理分析-Task调度对象实现接口(Schedulable)原理分析
我们知道,任务调度器(TaskScheduler)中的调度对象分为两类:Pool和TaskSetManager。而这两类调度对象都实现了接口Schedulable。这篇文章着重讲解其中的一类调度对象Pool的实现原理。

在Pool调度对象中实现了两种调度算法,本文会详细讲解两种算法的实现原理。

Pool介绍

Pool是一个Schedulable实体,它包含TaskSetManagers或其Pools的集合。

Pool声明

Pool的类声明如下:

private[spark] class Pool(
    val poolName: String,
    val schedulingMode: SchedulingMode,
    initMinShare: Int,
    initWeight: Int)
  extends Schedulable 

Pool的成员分析

  • parent
 var parent: Pool = null

通过该变量可以把任务形成一个任务树。

  • schedulableQueue
    声明如下:
  val schedulableQueue = new ConcurrentLinkedQueue[Schedulable]

保存可调度对象的同步队列。

  • schedulableNameToSchedulable

调度对象名称和调度对象的映射,这样可以通过调度名称获取到对应的调度对象。

  val schedulableNameToSchedulable = new ConcurrentHashMap[String, Schedulable]
  • checkSpeculatableTasks
override def checkSpeculatableTasks(minTimeToSpeculation: Int): Boolean

该函数用来检测是否任务的调度时间已经超过了设定的阈值。

  • taskSetSchedulingAlgorithm
private val taskSetSchedulingAlgorithm: SchedulingAlgorithm

用来保存调度算法对象。目前支持两种调度算法:FIFO和FAIR。下一节会详细讲解两种算法的实现原理。

  • addSchedulable

功能:向调度对象队列中添加调度对象。

扫描二维码关注公众号,回复: 4481666 查看本文章
  override def addSchedulable(schedulable: Schedulable) {
    require(schedulable != null)
    schedulableQueue.add(schedulable)
    schedulableNameToSchedulable.put(schedulable.name, schedulable)
    schedulable.parent = this
  }
  • removeSchedulable
  override def removeSchedulable(schedulable: Schedulable) 

和addSchedulable函数相似,该函数只不从同步队列中删除调度对象。

  • getSchedulableByName
override def getSchedulableByName(schedulableName: String): Schedulable = {

通过调度对象的name字段的值来获取调度对象。可以从同步队列ConcurrentLinkedQueue中获取,也可以从schedulableNameToSchedulable映射变量中获取。

  • getSortedTaskSetQueue
  override def getSortedTaskSetQueue: ArrayBuffer[TaskSetManager]

该函数很重要,通过该函数可以得到按调度算法排好序的调度对象队列。

  • 运行任务数的统计
def increaseRunningTasks(taskNum: Int)
def decreaseRunningTasks(taskNum: Int)

这两个函数用来操作runningTasks变量,统计目前正在运行的任务数。同时也会把parent的任务数进行对应的进行增减操作。

调度算法

接口

private[spark] trait SchedulingAlgorithm {
  def comparator(s1: Schedulable, s2: Schedulable): Boolean
}

FIFO调度算法(FIFOSchedulingAlgorithm)

FIFO调度算法的实现类是:FIFOSchedulingAlgorithm。该类实现了接口SchedulingAlgorithm中的comparator函数。

该函数先比较调度对象s1和s2的优先级(priority)字段的值,若相等再比较s1和s2的stageId值的大小。详细的实现逻辑如下:

FAIR调度算法(FairSchedulingAlgorithm)

FAIR调度算法的实现类是:FairSchedulingAlgorithm。它通过minShare,runningTasks和weight的变量值来比较调度的优先级。

该算法的流程如下图所示:

通过上面的流程图可知:
在对两个调度实体进行调度优先级对比时,若第一个调度实体正在运行的任务数小于第一个调度实体的CPU数量,则任务第一个实体优先级高,否则认为第二个调度实体的优先级高。即比较以下两个值s1Needy和s2Needy的大小:

val minShare1 = s1.minShare
val minShare2 = s2.minShare
val runningTasks1 = s1.runningTasks
val runningTasks2 = s2.runningTasks
val s1Needy = runningTasks1 < minShare1
val s2Needy = runningTasks2 < minShare2

若两个实体的运行任务数都小于CPU数,则计算每个调度实体的运行任务数和CPU数的比例,并对这个比例进行比较。若第一个的占有比率小于第二个,则认为第一个调度实体的优先级高,否则认为第二个的优先级高。即比较以下两个值的大小:

val minShareRatio1 = runningTasks1.toDouble / math.max(minShare1, 1.0)
val minShareRatio2 = runningTasks2.toDouble / math.max(minShare2, 1.0)

若这两个实体的调度比率相等,则计算运行任务数和调度实体的权重(weigth)的比率,若第一个的比率小于第二个,则认为第一个的比第二个优先级高,否则认为第二个优先级高。即比较以下两个值的大小:

val taskToWeightRatio1 = runningTasks1.toDouble / s1.weight.toDouble
val taskToWeightRatio2 = runningTasks2.toDouble / s2.weight.toDouble

若相等,则直接比较两个调度实体的name的ascii码。

总结

本文描述了可调度对象Pool的实现原理。该对象实现了任务调度算法,目前支持两种:FIFO和FAIR。通过该对象可以把整个stage的任务形成一颗树状的结构。

猜你喜欢

转载自blog.csdn.net/zg_hover/article/details/84670461