Jeremy

当你的才华还撑不起你的野心时,你就该静下心来学习。

© Jeremy | Powered by LOFTER

Hadoop-Yarn资源调度器

1.资源调度器背景

    理想中,我们希望对于任何一个yarn应用对于资源(cpu、内存、IO等)的请求都能立即满足,可是现实是资源是有限的,在一个很忙的集群中,往往需要等资源有效后才能满足自己的请求。

    前面提到过Yarn中的ResourceManager主要负责集群资源的管理与调度,资源调度器是Yarn中最核心的组件之一,Yarn资源调度器负责来给不同应用分配资源,调度策略是可配置的,且是插拔式的。

Yarn自带了FIFO、Capacity Schedule、Fair Schedule三种常用调度器。用户可按照接口规范编写一个新的资源调度器,并通过简单的配置使之运行起来,Capacity Schedule是默认的调度器。

FIFO它属于批处理调度器,先进先分配资源,这样会导致应用的排队等待,不适合大的资源共享型集群。而后两个属于多租户调度器,它采用树形多队列的形式组织资源(层级队列管理机制以后介绍),更适合公司共享资源型应用场景。

2.Capacity Schedule资源调度器

Capacity Schedule调度器以队列为单位划分资源,队列以分层方式组织资源,设计了多层级别的资源限制条件以更好的让多用户共享一个Hadoop集群,比如队列资源限制、用户资源限制、用户应用程序数目限制。队列里的应用以FIFO方式调度,每个队列可设定一定比例的资源最低保证和使用上限,同时,每个用户也可以设定一定的资源使用上限以防止资源滥用。而当一个队列的资源有剩余时,可暂时将剩余资源共享给其他队列。


图为一个大job和一个小job在Capacity Schedule调度器下随时间变化资源利用情况


为了方便了解Capacity Schedule,从配置文件举个例子解释比较清楚,Capacity Schedule有自己的配置文件,在/etc/hadoop/capacity-Scheduler.xml。

假设一个队列的层级结构如下:

root

    ├── prod

    └── dev

        ├── eng

        └── science

在队列root中定义了prod和dev两个队列,分别占用40%和60%的容量,通过设置yarn.scheduler.capacity.<queue-path>.<sub-property>属性来配置一个队列,<queue-path>就是队列的层级目录,比如root.dev.

配置文件如下:

<?xml version="1.0"?>

<configuration>

  <property>

<name>yarn.scheduler.capacity.root.queues</name>

<value>prod,dev</value> </property>

<property>

<name>yarn.scheduler.capacity.root.dev.queues</name>

<value>eng,science</value> </property>

<property>

<name>yarn.scheduler.capacity.root.prod.capacity</name>

<value>40</value> </property> <property>

<name>yarn.scheduler.capacity.root.dev.capacity</name>

<value>60</value> </property> <property>

<name>yarn.scheduler.capacity.root.dev.maximum-capacity</name>

<value>75</value> </property> <property>

<name>yarn.scheduler.capacity.root.dev.eng.capacity</name>

<value>50</value> </property> <property>

<name>yarn.scheduler.capacity.root.dev.science.capacity</name>

<value>50</value> </property>

</configuration>

    配置文件中定义了prod和dev两个队列,容量分别是集群资源的40%和60%,dev分为eng和science两个容量相等的子队列,dev队列限制了最大使用资源上限75%,即如果dev的容量60%用完了,在prod有空闲的资源下可以供dev使用15%。换句话说,prod队列始终会有25%的空闲资源供直接使用。另外,dev下的两个子队列eng和science没有设置最大使用资源上限值,所以,这两个子队列默认都可以用完dev所有的容量(最大75%),同理,prod也没有设置最大使用资源上限,因此,prod最大可用整个集群资源即100%。

    除了配置队列的层级结构和容量,还可以通过配置属性来控制一个用户或者应用可以分配的最大资源数目,还可以配置同时运行的用户应用程序数目,以及队列的ACLs(访问控制列表)。yarn.scheduler.capacity.<queue-path>.user-limit-factor控制队列使用比例,值为0.0-1.0

    当应用需要指定使用哪个队列,需要指定对应 应用的属性,比如mapreduce,通过属性mapreduce.job.queue name来设置。如果没有设置,则默认使用一个叫‘default’的队列。对于Capacity Schedule,指定队列名只需指定层级结构中的最后一级,比如prod和eng即可,而dev.eng者root.dev.eng都不能识别。

Capacity Schedule资源调度器主要有以下几个特点:

  1. 容量保证:可为每个队列设置资源最低量和资源使用上限,而所有提交到该队列的应用程序共享该队列中的资源;

  2. 灵活性:如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用程序提交,则其他队列释放的资源会归还给该队列,这种资源灵活分配的方式明显可以提高资源的利用率;

  3. 多租户:支持多用户共享集群和多应用程序同时运行,为防止当个应用或者用户或者队列独占集群资源,可为之增加限制,比如设置一个用户或者应用程序可以分配的最大资源数、最大任务运行数;

  4. 安全保证:每个队列有严格的ACLs列表规定它的访问用户,每个用户可以指定其他哪些用户允许查看自己应用程序的运行状态或者控制应用程序(比如kill);

  5. 动态更新配置文件:管理员可以根据需要动态更改各种配置参数,以实现在线集群管理。

3.Fair Schedule资源调度器

Fair Schedule调度器同Capacity Schedule类似,以队列为单位划分资源,队列以分层方式组织资源,同样提供多层级资源限制条件,比如队列资源限制、用户资源限制、用户应用程序数目限制。队列内的资源共享方式可以自行配置,FIFO或者Fair等,每个队列可设定一定比例的资源最低保证和使用上限,同时,每个用户也可以设定一定的资源使用上限以防止资源滥用。而当一个队列的资源有剩余时,可暂时将剩余资源共享给其他队列。


为了更好的理解资源在队列之间共享,举个例子,假设有两个用户A和B,他们拥有自己的队列池,A启动一个job,这时,该job被分配了所有的有效集群资源,然后B再启动一个job,A仍然在运行中,这时A和B分别被分配了一半的资源,而后,B再启动一个job,假设其他两个job仍在运行,这时B的两个job共享B所拥有的集群的一半的资源,即分别拥有1/4的整个集群资源。


Fair sharing between user queues

它与Capacity Schedule不同之处有:

  1. 资源公平共享:在每个队列中,Fair Schedule可选择按照FIFO、Fair或DRF策略为应用程序分配资源,默认采用Fair,Fair策略是一种基于最大最小公平算法实现的资源多路复用方式。

  2. 支持资源抢占:当某个队列中有剩余资源时,调度器会将这些资源共享给其他队列,而当该队列中有新的应用程序提交时,调度器要为它回收资源。为了尽可能降低不必要的计算浪费,调度器采用了先等待再强制回收的策略,即如果等待一段时间(defaultMinSharePreemptionTimeout属性设置,默认;minSharePreemptionTimeout单独设置某个队列)后尚有未归还的资源,则会进行资源抢占,从那些超额使用资源队列中kill一部分任务,进而释放资源。但这种方式降低了集群的效率,因为被杀的任务涉及的containers需要重新被执行。通过yarn.scheduler.fair.preemption属性来开启抢占功能(全局)。

  3. 负载均衡:提供了一个基于任务数目的负载均衡机制,该机制尽可能将系统中的任务均分分配到各个节点上。

  4. 调度策略配置灵活:允许为每个队列单独设置调度策略(FIFO、Fair或DRF)

  5. 提高小应用程序响应时间:采用最大最小公平算法,小作业可以快速获取资源并运行完成。

说明:

  • minSharePreemptionTimeout 最小共享量抢占时间,表示一个资源池在该时间内使用的资源量一直低于设置的最小资源量,则开始抢占;

  • defaultMinSharePreemptionTimeout最小共享量抢占时间默认值;

  • defaultFairSharePreemptionTimeout公平共享量抢占时间默认值

  • fairSharePreemptionTimeout公平共享量抢占时间

还是从配置文件举个例子:

Fair Schedule允许单独将队列配置信息放到一个配置文件里,默认是fair-schedule.xml,通过classpath加载.

比如:

<?xml version="1.0"?>

<allocations> 

    <defaultQueueSchedulingPolicy>fair</defaultQueueSchedulingPolicy>

    <queue name="prod">

        <weight>40</weight>

        <schedulingPolicy>fifo</schedulingPolicy> 

    </queue>

    <queue name="dev"> 

        <weight>60</weight> 

        <queue name="eng" /> 

        <queue name="science" />

    </queue>

    <queuePlacementPolicy>

        <rule name="specified" create="false" />

        <rule name="primaryGroup" create="false" /> 

        <rule name="default" queue="dev.eng" />

    </queuePlacementPolicy>

</allocations>

配置文件定义了队列的层级结构,并且定义了队列prod和dev的资源权重40:60,此处不是代表百分数,该权重是公平算法中用来计算用的。比如也可以定义为2和3;

  • defaultQueueSchedulingPolicy属性指定的是所有队列内部资源调度方式,默认fair,可以省略不配置,也可以单独指定每个队列的调度方式,通过schedulingPolicy设置来覆盖默认的调度方式,比如这里的prod队列设置为FIFO,prod和dev还是fair调度方式;

  • queuePlacementPolicy属性用来配置任务放置策略,即提交的应用任务被放入哪个队列,会以轮询方式来匹配规则,specified表示通过应用自身指定,如果没有指定或者不存在的话,不会创建,而是匹配下一个规则即primaryGroup,表示的是放入该用户所属组的队列中,如果所属组中没有队列,则放入默认的队列中,即dev.eng中。

  • 如果queuePlacementPolicy属性没有设置,将会遵循以下规则:

<queuePlacementPolicy>

    <rule name="specified" /> 

    <rule name="user" />

</queuePlacementPolicy>

即如果没有指定队列名,则将用户的名字当成放入的队列名,如果队列不存在,则创建。

  • 还有一种放置策略,将所有的应用都放在默认的队列中,如下定义:

<queuePlacementPolicy>

    <rule name="default" />

</queuePlacementPolicy>

两种调度器的比较




评论