一、概述
公平调度器可以为所有的应用“平均公平”分配资源,当然,这种“公平”是可以配置的,称为权重,可以在分配文件中为每一个队列设置分配资源的权重,如果没有设置,默认是1(由于默认权重相同,因此,在不做配置的情况下,作业(队列)之间的资源占比相同)。
默认地,所有的应用程序在一段时间内平均获得相等的资源份额;
默认地,公平调度程序仅基于内存调度公平决策,当然,这种策略也是支持配置的。
其策略如下图所示:
紫色区域代表任务A, 绿色区域代表任务B,当只有一个应用程序(A)在运行时,该应用程序将使用整个集群的资源(0 ~ t1时间段)。当提交其他应用程序时(t1时刻),A释放的资源被分配给新应用程序,因此每个应用程序最终得到的资源大致相同(在默认情况下)。当任务B执行完后(t2时刻),B所占用的资源又会被A使用,此后A又将完全占用集群资源直至任务结束。
相比较容量调度器,公平调度器并不会为某个队列预留资源,调度器会在所有正在运行的作业之间动态平衡集群资源。公平调度器的这种机制不光实现应用之间的公平分配资源,也可以实现在多队列之间,因为公平调度器也支持多层级队列。但是公平规则只限于同级队列。例如:默认配置下,队列A、B,A启动一个作业,此时A占用100%资源,过一段时间,B队列启动一个作业b1,而后A、B将平分资源,各占50%,如果此时B队列又启动了一个作业b2,那么b1、b2将各占队列B的50%资源,即a1作业占系统资源的50%,b1、b2各占系统资源的25%。
二、配置
1. 指定调度器
位置:$HADOOP_HOME/etc/hadoop/yarn-site.xml
添加配置:
key: yarn.resourcemanager.scheduler.class
value: org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler
2. 定义分配文件
位置:$HADOOP_HOME/etc/hadoop/fair-scheduler.xml
队列结构:
(root)
--general
--dev
--mr
--azkaban
队列元素使用<queue/>来定义,权重使用其子元素<weight/>定义,上面的结构在配置文件中如下:
<queue name="general">
<weight>2</weight>
<schedulingPolicy>fifo</schedulingPolicy>
</queue>
<queue name="dev">
<weight>8</weight>
<queue name="mr"></queue>
<queue name="azkaban"></queue>
<schedulingPolicy>drf</schedulingPolicy>
</queue>
该配置文件中,队列general占用资源权重20%,dev队列占用权重80%,也就是说,如果集群资源分配比例是1:4,那么此时就认为是公平的。对于dev的子队列mr和azkaban,由于没有分配权重,因此默认都是1,也就是说,mr和azkaban队列平分dev的资源。
每个队列可以拥有自己的调度策略,可选值又fifo、fair(默认)、drf,可以使用<queue/>的子元素<schedulingPolicy/>定义。
和容量调度器相同,公平调度器也可以配置最大(<queue/>子元素<maxResources/>)、最小资源(<queue/>子元素<minResources/>)以及最大可运行应用数量(<queue/>子元素<maxRunningApps/>),其中最小资源可以确保特定用户、群组或生产应用程序总能获取到足够的资源时是很有用的。当一个资源池包含作业时,它至少能获取到它的最小共享资源,但是当资源池不完全需要它所拥有的保证共享资源时,额外的部分会在其它资源池间进行切分(摘自 hadoop2配置公平调度器)。
配置好后,进入YARN的控制台,如图所示:
三、队列放置
不同于容量调度器,公平调度器设计了一个基于规则的系统来为作业分配调度队列,它内置了一套规则可以插拔式的配置。定义分配规则使用<queuePlacementPolicy/>标签,具体条件使用<rule/>定义,例如:
<queuePlacementPolicy>
<rule name="specified" create="false"></rule>
<rule name="primaryGroup" create="false"></rule>
<rule name="user" create="false"></rule>
<rule name="default" queue="general"></rule>
</queuePlacementPolicy>
我们可以将<rule>视为web中的过滤器,当对作业进行分配的时候,系统会从上到下一次匹配,例如上面的配置,specified表示在提交作业的时候指定了队列,primaryGroup指的是用户所在unix用户组(组名)的队列,user值得是用户名为命名的队列,default规则是兜底规则,若以上都不匹配,则放到general队列。
create属性指定是,若匹配到已经存在的队列,则将作业放到改队列,若匹配不到已经存在的队列,则根据create来选择是否创建队列,默认值是true。例如,若<rule name="user" create=true/>,此时用户user1提交作业,调度器就会寻找是否又名字为user1的队列,若没有,就会创建名字为user1的队列,并将这个作业放到该队列中。
若不显示地配置<queuePlacementPolicy/>,则调度器将使用如下默认的配置:
<queuePlacementPolicy>
<rule name="specified"></rule>
<rule name="user"></rule>
</queuePlacementPolicy>
也就是说,除非显示地指明所用队列,否则按照提交作业的用户名为名加入队列中。
四、抢占
与容量调度器不通,公平调度器拥有抢占机制。当提交一个作业的时候,如果资源紧张,则作业会等待其他作业资源释放后再执行,这个等待时间可以使用抢占功能进行控制。
抢占指的是,调度器允许终止哪些占用资源高于公平状态下应分配的资源,从而释放资源给哪些占用资源小于公平状态下应分配资源的作业。
1. 开启抢占模式:
yarn.scheduler.fair.preemption=true
2. 抢占机制主要设置:
最小共享:指的是在这个时间内,没有获得设置的最小资源值,则会抢占其他容器资源。
配置:
方式1:顶层元素<defaultMinSharePreemptionTimeout/>,单位秒,可以为所有队列设置。
方式2:<queue/>子元素<minSharePreemptionTimeout>,单位秒,单独为某个队列设置。
显而易见,该种方式需要队列的最小资源设置配合。
公平共享:指的是在这个时间内,没有获得公平状态下的资源值的一半,则抢占其他容器资源。
配置:
方式1:顶层元素<defaultFairSharePreemptionTimeout/>,单位秒,可以为所有队列设置。
方式2:<queue/>子元素<fairSharePreemptionTimeout>,单位秒,单独为某个队列设置。
需要注意的是,抢占功能本身虽然会减少作业执行的延迟时间,但是会降低整个集群的效率,因为被抢占的作业会终止运行,最终会重新开始执行。
五、总结
公平调度器实现了较高的集群利用率,同时保证小作业能即使完成。