搜了一些博客,发现写得最清楚的还是《Hadoop权威指南》,以下内容主要来自《Hadoop The Definitive Guide》 4th Edition 2015.3。
Hadoop YARN Scheduler
三个调度器
YARN提供了CapacityScheduler, FairScheduler, FifoScheduler三个调度器,继承于AbstractYarnScheduler,Resource Manager通过调度器决定对提交application分配的资源大小。
CapacityScheduler首先将所有资源分配到hierarchical queue中,每个任务执行时指定对应的queue,使大任务不会占用整个集群的资源,通过对queue的资源管理提高整个集群的资源共享能力。通常会使小任务执行更快,大任务更慢。
Fair Scheduler 会在第一个任务运行时分配当前同级队列的所有资源,当有其它任务运行时,回收前面任务运行时的部分资源(一般为运行完成的Container)用于其它任务。
至于FIFO,源码里都没有描述,可能就是一般的先进先出了。
YARN默认使用CapacityScheduler,通过下面的属性配置:
yarn.resourcemanager.scheduler.class
org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler
YARN 动态资源分配
YARN 能够动态申请资源,如MapReduce中reduce的container会在map过程结束后申请。但Spark On YARN的机制为申请固定的executor,而不动态改变已申请的资源。
YARN上新运行的任务能够使用已运行任务回收的资源(如运行完Map task的container),甚至还能够通过强行结束先前任务的container抢占资源。
Capacity Scheduler
CapacityScheduler重点解决多个组织共享集群资源,并保证每个组织自己的资源使用量。当自己的资源不足时能够使用其它组织的空闲资源。
资源通过层级队列(hierarchical queues)的形式进行组织,配置在etc/hadoop/capacity-scheduler.xml.
yarn.scheduler.capacity.root.queues
a,b
The queues at the this level (root is the root queue).
yarn.scheduler.capacity.root.a.queues
a1,a2
The queues at the this level (root is the root queue).
yarn.scheduler.capacity.root.a.capacity
40
yarn.scheduler.capacity.root.b.capacity
60
yarn.scheduler.capacity.root.a.a1.capacity
50
yarn.scheduler.capacity.root.a.a2.capacity
50
yarn.scheduler.capacity.root.a.maximum-capacity
75
root
├── a 40%
| ├── a1 50%
| └── a2 50%
└── b 60%
上面的设置形成了如图的hierarchical queues,并指定a队列使用40%的资源,b队列60%,a1 a2各占a队列的50%,a队列在b队列资源空闲时,最高可占用集群75%的资源。
一些设置和特点
- 通过设置queue的maximum capacity能够避免使用相邻子队列的所有资源。
- 改变文件后需要运行
$HADOOP_YARN_HOME/bin/yarn rmadmin -refreshQueues
- 子队列能使用的最大资源为父队列的资源
- 队列上除了对资源的管理,还提供了运行的用户、应用数量等的限制功能。
- 默认只支持内存,通过配置可以支持CPU
Fair Scheduler (公平调度器)
对比CapacityScheduler的主要区别: 任务提交时占用同一层队列所有的资源 (Capacity Scheduler中只使用maximum-capacity限制下的其它队列闲置的资源),另一个任务提交时,会回收先前任务的部分资源。
fair
name="a">
4
fifo
name="a1" />
name="a2" />
name="b">
6
name="specified" create="false" />
name="primaryGroup" create="false" />
name="default" queue="a.a1" />
上面的配置文件给出了一个如下图的层级队列。
root
├── a (权重4 因此占用总体40%的资源)
| ├── a1 没有指定权重,因此与a2队列平分a队列40%的资源;队列内部的多个应用使用fifo策略。
| └── a2
└── b (权重6 因此占用总体60%的资源)
向a1队列中提交任务1时,首先会占用整个集群;向b队列提交任务2时,会从任务1中回收60%的资源用于任务2;向a1队列中继续提交任务3时,会按fifo的策略使用a队列的40%资源;向a2队列提交任务4时,会从a1队列的任务1、任务3中回收资源,使a1队列资源和a2队列相同。
在Hadoop Fair Scheduler的具体实现中,并没有对每个application实现绝对公平的资源分配,而是针对同一级队列内部的资源,队列内部可以选择其它的调度策略。并且使用weight参数,使相同层级的队列资源根据weight分配而非直接平均,设置不同weight后并不“fair”。(实质上和CapacityScheduler类似,都是对层级队列的管理,每一层的队列之间资源存在共享,有博客提到FairScheduler在不断的发展中已经能够实现大部分CapacityScheduler的功能,两者的功能越来越接近)
注意,Fair Scheduler会默认对每个用户创建一个queue用于没指定queue的任务,weight为1,因此要想忽略默认创建的用户queue,需要将权重设置偏大。
队列内部调度策略
每个队列内使用一定的调度策略,常见的FIFO、FAIR和DRF。
FIFO(first in first out), 先提交的任务先分配资源。
FAIR (max-min fairness), 先把资源平均分配,某些任务如果有多出资源则将多出的资源分配给其它任务,对资源要求低的任务优先。
DRF(dominant resource fairness),解决有多种资源(CPU、内存等)同时考虑的分配问题,如一个CPU要求高内存要求低与一个CPU要求低内存要求高的应用。