• 真实场景中,总会出现这样的情况:新提交的YARN应用需要等待一段时间,才能获得所需的资源。
  • 不能立即获得资源的应用,总不能直接拒绝,需要有个地方去存储这些应用 —— 使用队列
  • 同时,队列中的应用如何为其分配资源:是先到先得?还是优先执行资源需求较小的应用? —— 需要有特定的策略为应用分配资源
  • 而YARN的调度器(scheduler)的工作就是根据既定策略为应用分配资源

1. YARN中的三种调度器概述

1.1 FIFO调度器

  • FIFO调度器,顾名思义:将应用放置在一个队列中,按照到来的先后顺序(先进先出)运行应用。
  • 首先为队列中的第一个应用分配资源,等第一个应用的资源被满足后再依次为队列中其他应用分配资源

FIFO调度器的优缺点:

  1. 简单易懂,不需要任何的配置,但不适合共享集群
  2. 从上面的图示中可以看出:FIFO调度器容易使得小作业被阻塞,直到大作业执行完成。
  3. 使用容量(capacity)调度器或公平(fair)调度器更适合共享集群:都允许让长时间运行的作业能及时完成,同时还允许正在进行较小临时查询的用户能在合理的时间内得到返回结果。(不仅兼顾大作业,还能兼顾小作业

1.2 capacity调度器

  • 允许多个组织共享一个Hadoop集群,每个组织可以分配到集群资源的一部分。同时,为每个组织创建专门的队列,这样每个队列也就有了对应的集群资源。

capacity调度器的优缺点:

  1. 有的队列集群资源较少,可以专门用于运行小作业,保证小作业能及时运行
  2. 同时,这也牺牲了资源的利用率:队列资源为属于该队列的应用保留,如果没有应用被提交,则队列资源将处于空闲状态
  3. 当然,由于大作业无法使用全部的资源,大作业的执行时间会变长

1.3 fair调度器

  • 不需要为特定作业预留相应的资源,调度器会在所有运行的所有运行的作业中动态平衡资源
    ① 当第一个(大)作业启动时,它会占用所有的资源。
    ② 一段时间后,提交一个(小)作业。
    ③ 小作业需要等待大作业container使用完并释放资源,然后大作业和小作业可以同时运行,并各自分配到一半的资源。
    ④ 当小作业运行完成后,大作业可以再次使用全部的集群资源。

fair调度器的优点:

  1. 既得到了较高的集群利用率,有保证小作业能及时完成

1.4 总结一下

  • FIFO调度器:最简单的调度器,按照先进先出的顺序执行作业,容易使小作业被阻塞,不适合共享集群
  • capacity和fair调度器,既能允许长时间的作业及时完成,又能正在进行的较小临时查询能在合适的时间返回结果。
  • capacity调度器:为特定的作业预留资源,保证小作业能及时完成,大作业的执行时间变长,牺牲了资源的利用率。
  • fair调度器:为正在运行的作业动态平衡资源,既保证了较高的集群利用率,又保证了小作业能及时执行。

2. capacity调度器

  • capacity调度器,可以先按组织划分资源和队列。在同一组织中,按用户再进一步划分队列,使用组织内的不同用户可以共享该组织所分配的资源。
  • capacity调度器,队列内部按照FIFO调度策略执行应用。

capacity调度器的的弹性队列:

  1. 一个队列中的作业需要的资源不足,而其他队列的资源空闲。
  2. 这时,capacity调度器会将其他队列的空闲资源分配给队列中的作业,即使超过了队列所声明的资源容量。
  3. 如果一个队列中资源被分配给了其他队列,当自己的资源不足时,无法强制终止container以抢占资源
  4. 因此,为了避免过度使用其他队列中的资源,需要为队列设置一个最大容量限制
  5. 最大容量限制,牺牲了队列弹性,需要不断尝试,找到一个折中。

如何配置capacity调度器

  1. 配置文件名为:capacity-scheduler.xml
  2. 假设一个队列层次结构如下
root
  |__ prod: 40%, 默认最大容量为100%
  |__ dev: 60%, 指定最大容量:75%
       |__ eng: 50%, 默认最大容量100% * dev的容量
       |__ science: 50%, 默认最大容量100% * dev的容量
  1. 队列的配置属性:yarn.scheduler.capacity.<queue-path>.<sub-prooperty>进行配置
<?xml version="1.0"?>

<configuration>
    <!-- 定义root队列的两个子队列 -->
    <property>
        <name>yarn.scheduler.capacity.root.queues</name>
        <value>prod, dev</value>
    </property>

    <!-- 定义dev队列的两个子队列 -->
    <property>
        <name>yarn.scheduler.capacity.root.dev.queues</name>
        <value>eng, science</value>
    </property>

    <!-- 队列prod占40%的容量 -->
    <property>
        <name>yarn.scheduler.capacity.root.prod.capacity</name>
        <value>40</value>
    </property>

    <!-- 队列dev占60%的容量 -->
    <property>
        <name>yarn.scheduler.capacity.root.dev.capacity</name>
        <value>60</value>
    </property>

    <!-- 定义dev队列的最大容量为75,避免占用所有集群资源-->
    <property>
        <name>yarn.scheduler.capacity.root.dev.maximum-capacity</name>
        <value>75</value>
    </property>

    <!-- 队列eng占dev队列50%的容量,默认最大容量为dev队列100%-->
    <property>
        <name>yarn.scheduler.capacity.root.dev.eng.capacity</name>
        <value>50</value>
    </property>

    <!-- 队列science占dev队列50%的容量,默认最大容量为dev队列的100% -->
    <property>
        <name>yarn.scheduler.capacity.root.dev.science.capacity</name>
        <value>50</value>
    </property>
</configuration>

队列放置

  1. 实际是应用的放置,即应用应该放置到哪个队列中
  2. 在MR程序中,可以通过设置mapreduce.job.queuename属性来指定应用使用哪个队列
  3. 如果指定的队列不存在,提交时会报错
  4. 如果不指定队列,默认使用default队列

3. fair调度器

(1)fair调度器的概念:

  • fair调度器旨在为所有正在运行的应用,公平地分配资源
  • 注意: 这里的公平并非平均分配的意思,而是按照配置文件中指定的比例进行分配。
    ① 例如,设置两个队列A和B,资源分配的比例为3:2。
    ② 当系统中同时运行一个A队列的应用1和一个B队列中的应用2时,应用1将获得集群60%的资源,而应用2将获得集群40%的资源

(2)以两个用户A和B分别对应队列A和B,且资源比例为1: 1为例:

  1. 最开始时,A启动一个作业1。由于没有其它作业运行,则作业1将获得所有的集群资源
  2. 一段时间后,B启动作业2。等待一段时间后,作业1和作业2将分别使用集群一半的资源
  3. 又过了一段时间,B启动作业3。等待一段时间后,作业2和作业3将分别使用队列B一半的资源,即分别使用集群四分之一的资源。

(3)fair调度器的配置:

  1. 开启fair调度器:开源Hadoop默认使用capacity调度器(CDH默认使用公平调度器),需要将yarn-site.xml中设置如下内容才能开启fair调度器。
<property>
    <name>yarn.resourcemanager.scheduler.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
</property>
  1. 通过fair-scheduler.xml配置fair调度器
<?xml version="1.0"?>

<allocations>
    <!-- 默认调度策略,默认值fair -->
    <defaultQueueSchedulingPolicy>fair</defaultQueueSchedulingPolicy>

    <queue name="prod">
        <!-- 权重,默认值1 -->
        <weight>40</weight>
        <schedulingPolicy>fifo</schedulingPolicy>
    </queue>

    <queue name="dev">
        <weight>60</weight>
        <queue name="eng"/>
        <queue name="science"/>
    </queue>

    <!-- 队列放置策略,逐个匹配知道成功,default是兜底的规则
  	  specified,用户指定的队列
   	  primaryGroup,用户所在unix组名命名的队列
      上述规则均不满足,触发default规则,把应用放在dev.eng队列中
    -->
    <queuePlacementPolicy>
        <rule name="specified" create="false"/>
        <rule name="primaryGroup" create="false"/>
        <rule name="default" create="dev.eng"/>
    </queuePlacementPolicy>
</allocations>
  1. 通过修改yarn-site.xml中如下属性,来修改文件名
<property>
    <name>yarn.scheduler.fair.allocation.file</name>
    <value>xxxxx</value>
</property>
  • fair队列内部还可以使用FIFO或DRF(主导资源公平性)策略进行资源调度

(4)队列放置:

  1. 按照队列分配文件中的策略进行放置
  2. 如不指定放置策略,则默认使用如下策略:
<queuePlacementPolicy>
    <rule name="specified" />
    <rule name="user" />
</queuePlacementPolicy>

(5)fair调度器支持抢占

  1. 允许调度器终止超过指定份额资源的队列中的container,将释放后的资源分配给低于应得份额资源的队列。
  2. 通过将yarn.scheduler.fair.preemption设置为true,开启fair队列的抢占功能
  3. 设置minimum share preemption timeout:在指定时间内,未获得承诺的最小份额,调度器则开始抢占其他container
  4. 设置fair share preemption timeout:在指定时间内,未获得指定比例的资源,调度器则开始抢占其他container

4. 延迟调度

  • 一个应用请求某个节点,该节点没有空闲container,则转去向其他节点申请container
  • 通过本地限制,我们可知:一般,第一次请求的节点是满足本地化原理的,可以提高集群的效率
  • 实验表明,该应用如果等待一小段时间,具可以戏剧性地应用增加在本地节点运行的机会 —— 延迟调度可以提高集群的效率
  • capacity调度器和fair调度器都支持延迟调度。

调度机会:

  1. Node manager会周期性地向Resource Manager发送心跳请求,包含正在运行的container、新container可以使用的资源等信息。
  2. Node managerResource manager发送心跳时,就是应用潜在的一次调度机会。
  3. 使用延迟调度时,调度器在等待设定的最大调度次数后,才放松本地限制接收下一次调度机会

延迟调度的三种设置:

  1. capacity调度器:通过设置yarn.scheduler.capacity.node-locality-deley(正整数),调度器放松本地限制,转去匹配同一机架的其他节点前,等待的最大调度机会数
  2. fair调度器:通过yarn.scheduler.fair.locality.threshold.node(小数),调度器转去匹配同一机架的其他节点前,集群中的多少比例的其他节点提供了调度机会
  3. fair调度器:通过设置yarn.scheduler.fair.locality.threshold.rack,调度器转去匹配其他机架上的节点所需等待的时间阈值。
  • 目的:尽可能通过本地化,提高集群的效率
  • NM与RM之间的心跳,一次心跳为一次调度机会
  • 三种配置:
  1. 超过指定调度次数,匹配同一rack‘的其他节点
  2. 超过比例,匹配同一rack的其他节点
  3. 超过时间阈值,匹配其他rack的节点

5. 主导资源公平性 DRF

  • YARN的DRF(dominant resource fairness)算法,需要参考其他资料
  • 后续如果学习了,会进行补充

6. 总结

  • 三种调度器各自的优缺点:
  1. FIFO调度器: 简单易懂,先进先出,容易使小作业阻塞,不适合共享集群
  2. capacity调度器和fair调度器:适合共享集群,既能允许长时间运行的作业及时完成,又能保证小作业在合适的时间内完成
  3. capacity调度器: 为特定应用分配具有特定资源的队列,保证小作业立即执行,牺牲了集群的利用率,大作业执行时间变长
  4. fair调度器: 为正在运行的应用动态平衡资源,提高了集群利用率,有保证小作业能及时完成
  • capacity调度器:
  1. 队列内,采用FIFO调度策略
  2. 支持弹性队列: 允许将其他队列的空闲资源分配给资源不足的队里,即使操作队列声明的容量;为避免过度占用其他队列的资源,需要设置最大容量
  3. capacity调度器的配置:不设置最大容量,则可以使用所在层级的所有资源
  4. 队列放置:应用应该放置到哪个队列,先按specified,不存在则报错;不指定,按default
  • fair调度器:
  1. fair调度器中,队列的资源配置并非1: 1,而是由分配文件中比例决定
  2. 开源Hadoop默认使用capacity调度器,使用fair调度器需要进行配置才能开启
  3. fair调度器的配置:队列内的调度策略可以是fair、FIFO和DRF
  4. 放置策略:默认放置策略是先specified,再user
  5. 支持抢占:终止超过资源份额的队列中的container,将释放后的资源资源分配非低于份额的队列中的container;最小共享抢占和公平共享抢占
  • 延迟调度:
  1. 等待一定次数的调度机会,才放松本地限制,以金最大可能地利用本地化,提高集群效率
  2. 调度机会:Node managerResource manager发送心跳,是一次潜在的调度机会
  3. capacity调度器的配置:设置转去匹配同一机架其他节点的最大等待的调度机会次数
  4. fair调度器的配置:转去匹配同一机架其他节点的调度机会比例,转去匹配其他机架节点的等待时间阈值。