理想情况下,我们对Yarn的资源申请应该立即得到满足,但实际情况下整个集群的资源总量是有限的,这时就依赖资源调度器对资源进行调度了.
但在实际过程中,资源的调度策略本身就是一个难题,很难有一个完美的调度策略可以适用与所有的情况,为此Yarn提供了三种调度器让我们自行选择适用
FIFO调度器
这种调度会把所有资源申请放入一个队列先进先出.这是最简单的调度,也不需要任何配置,但这种调度器不适用共享集群环境.原因很简单,先入的大任务,会卡死后面的资源申请.
Capacity调度器
Capacity调度说明
这种调度运行多个组织共享集群,每个组织都可以获得集群的一部分计算能力.
通过为每一个组织都设置一个队列(队列树),再为每个队列都分配一定的集群资源,这样集群就可以为多个组织同时提供服务了.
在每个队列之内,资源将进行垂直划分,这样每个组织的成员将可以共享队列内部的资源.但在队列内部,依然是先进先出策略.
如果某个组织的资源已经全部用完而又急需分配,Yarn可能会将其它队列资源分配给它,这就是弹性队列,这时需要为队列设置一个最大资源使用量,防止抢夺太多的空闲资源
Capacity使用说明
conf/yarn-site.xml 配置启用Capacity调度器
yarn.resourcemanager.scheduler.class 设置为 org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
conf/capacity-scheduler.xml配置具体的队列树,一个例子如下:
<!--资源分配限制-->
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>a,b</value>
<description>根节点下定义a,b两个子队列</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.queues</name>
<value>a1,a2</value>
<description>队列a之下再定义a1,a2两个子队列</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.b.queues</name>
<value>b1</value>
<description>队列b之下定义b1子队列</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.capacity</name>
<value>40</value>
<description>int,定义a队列总体使用40%的资源</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.maximum-capacity</name>
<value>60</value>
<description>int,定义a队列最多使用60%的资源(弹性队列情况),如果设为-1则表示禁止弹性队列情况</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.minimum-user-limit-percent</name>
<value>25</value>
<description>int,定义a队列中对单一用户而言最多使用队列25%的资源(多个用户抢占,资源紧张发生争用时),如果设为100则表示不禁止单个用户使用上限</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.user-limit-factor</name>
<value>1.5</value>
<description>float,定义a队列对单一用户而言最多使用队列maximum-capacity*1.5的资源(单个或少量用户,资源大量空闲的时候)</description>
</property>
<!--任务&应用程序运行限制-->
<property>
<name>yarn.scheduler.capacity.maximum-applications</name>
<value>100</value>
<description>int,定义整个队列树的每个队列同时运行或者等待的最大任务数.(硬性限制,之外的请求将直接拒绝),默认10000</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.maximum-applications</name>
<value>200</value>
<description>int,对队列a或子队列同时运行或者等待的最大任务数.(硬性限制,之外的请求将直接拒绝),默认10000</description>
</property>
<property>
<name>yarn.scheduler.capacity.maximum-am-resource-percent</name>
<value>0.1</value>
<description>float,定义整个队列树的可用于运行的ApplicationMaster的最大百分比资源(一般用于限制应用程序的并发限制),默认0.1(10%)</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.maximum-am-resource-percent</name>
<value>0.1</value>
<description>float,对队列a或子队列的可用于运行的ApplicationMaster的最大百分比资源(一般用于限制应用程序的并发限制),默认0.1(10%)</description>
</property>
<!--队列管理&权限-->
<property>
<name>yarn.scheduler.capacity.root.b.state</name>
<value>STOPPED</value>
<description>RUNNING,STOPPED 设定队列状态.如果队列被设定为停止,则不能提交任何应用程序给它以及它的子队列</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.acl_submit_applications</name>
<value>*</value>
<description>限制哪些用户可以向队列a提交应用程序,*表示不限</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.acl_administer_queue</name>
<value>*</value>
<description>限定哪些用户可以管理队列a中的应用程序</description>
</property>
<!--其它-->
<property>
<name>yarn.scheduler.capacity.resource-calculator</name>
<value>org.apache.hadoop.yarn.util.resource.DefaultResourseCalculator</value>
<description>资源比较调度器设置.默认为DefaultResourseCalculator只用内存比较,DominantResourceCalculator多维比较</description>
</property>
<property>
<name>yarn.scheduler.capacity.node-locality-delay</name>
<value>5</value>
<description>为错过调度机会的任务建立局部处理容器,应设置为集群节点数量,默认为40</description>
</property>
Fair调度器
Fair调度器力求让所有用户公平(加权公平)的获得资源.
Fair调度器的配置文件fair-scheduler.xml文件
若没有这个配置文件,调度器会在用户提交第一个应用时为其自动创建一个队列,队列的名字就是用户名,所有的应用都会被分配到相应的用户队列中
启用公平调度器
yarn-site.xml
<property>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
</property>
yarn-site.xml公平调度配置节:
yarn.scheduler.fair.allocation.file 公平调度配置文件地址,默认为 fair-scheduler.xml
yarn.scheduler.fair.user-as-default-queue 是否使用用户名作为默认队列名称,如果队列名称没有指定。如果这个设置为“false”或未设置,所有工作有一个共享的默认队列,命名为“默认”。默认值为true。如果队列安置政策是在配置文件中,该属性将被忽略
yarn.scheduler.fair.preemption 是否使用资源抢占,默认为false
yarn.scheduler.fair.preemption.cluster-utilization-threshold 在该阈值之后发生抢占,默认为0.8
yarn.scheduler.fair.sizebasedweight 在队列内部分配资源时,默认采用公平轮询的策略分配资源,该配置将改变策略为按照应用程序资源需求数目分配资源,即应用程序需求越多,分配的资源越多.默认为false
yarn.scheduler.fair.assignmultiple 是否启动批量分配功能.当一个节点出现大量资源时,可以一次分配完成,也可以多次分配完成。默认值为false
yarn.scheduler.fair.max.assign 如果启动批量分配功能,则指定一次分配的最大Container数量。默认为-1没有限制
yarn.scheduler.fair.locality.threshold.node 当应用程序请求某个节点上资源时,它可以接受的可跳过的最大资源调度机会.默认情况下,该值为-1.0,表示不跳过任何调度机会
当按照分配策略,可将一个节点上的资源分配给某个应用程序时,如果该节点不是应用程序期望的节点,可选择跳过该分配机会暂时将资源分配给其他应用程序,直到出现满足该应用程序需的节点资源出现。
通常而言,一次心跳代表一次调度机会,而该参数则表示跳过调度机会占节点总数的比例
yarn.scheduler.fair.locality.threshold.rack 当应用程序请求某个机架上资源时,它可以接受的可跳过的最大资源调度机会。默认值为-1.0时表示没有通过任何调度的机会
yarn.scheduler.fair.allow-undeclared-pools 禁止自动创建(提交队列不存在)队列。默认值为true。如果队列安置政策是在配置文件中,该属性将被忽略
yarn.scheduler.fair.update-interval-ms 锁定的时间间隔调度器,重新计算需求,并检查是否将抢占间隔时间。默认为500毫秒
yarn.scheduler.increment-allocation-mb 内存规整化单位,默认是1024,这意味着,如果一个Container请求资源是1.5GB,则将被调度器规整化为ceiling(1.5 GB / 1GB) * 1G=2GB
yarn.scheduler.increment-allocation-vcores:虚拟CPU规整化单位,默认是1,含义与内存规整化单位类似
队列配置文件(可以在运行时完成修改最小共享,资源限制,权重,超时抢占以及队列调度策略等。调度器会每个10-15秒重载修改后的该配置文件):
quque
minResources:最少资源保证量,设置格式为“X mb, Y vcores”
当一个队列的最少资源保证量未满足时,它将优先于其他同级队列获得资源,对于不同的调度策略(后面会详细介绍),最少资源保证量的含义不同,
对于fair策略,则只考虑内存资源,即如果一个队列使用的内存资源超过了它的最少资源量,则认为它已得到了满足;对于drf策略,则考虑主资源使用的资源量,即如果一个队列的主资源量超过它的最少资源量,则认为它已得到了满足
maxResources:一个队列允许的最大资源,采用“X mb, Y vcores”的形式。对于单一资源公平策略,vcores的值会被忽略。一个队列永远不会分配资源总量超过这个限制
maxRunningApps:最多同时运行的应用程序数目。通过限制该数目,可防止超量Map Task同时运行时产生的中间输出结果撑爆磁盘
maxAMShare:限制队列用于运行Application Master的资源比例。这个属性只能用于叶子队列。比如,如果设置为1.0f,那么在这个队列的AMs可以占用100%的内存和CPU的公平共享。这个值为-1.0f将会禁用该特性并且amShare不会进行校验。默认值是0.5f
weight:与其他队列非比例的分享集群。权重默认是1,权重是2的队列将会收到接近默认权重2倍的资源
schedulingPolicy:任一队列都可以设置调度策略。允许的值包括“fifo”,“fair”,“drf”或者其他任何继承.默认fair
aclSubmitApps:可以提交apps到队列的用户或者组的列表。要获得更多信息可以参考下面的ACLs部分,关于列表的格式和ACLs如何发挥作用
aclAdministerApps:可以管理队列的用户或者组列表。当前唯一的管理动作就是杀死应用程序。要获得更多信息可以参考下面的ACLs部分,关于列表的格式和ACLs如何发挥作用
minSharePreemptionTimeout:队列处在最小共享之下,在尝试抢占其他队列的资源之前的秒数。如果不设置,队列将会总其父队列继承这个值
fairSharePreemptionTimeout:队列处在最小公平共享阈值之下,在尝试抢占其他队列的资源之前的秒数。如果不设置,队列将会总其父队列继承这个值
fairSharePreemptionThreshold:队列的公平共享抢占阈值。如果队列等待fairSharePreemptionTimeout之后没有接收到fairSharePreemptionThreshold*fairShare的资源,它被允许从其他队列抢占资源。如果不设置,队列将会总其父队列继承这个值
User
maxRunningApps:对特定用户可以运行的apps的数量限制
userMaxAppsDefault:设置任意用户(没有特定限制的用户)运行app的默认最大数量限制
defaultFairSharePreemptionThreshold:设置root队列的公平共享抢占的默认阈值;可以被root队列下的fairSharePreemptionThreshold 覆盖
queueMaxAppsDefault:设置队列的默认运行app数量限制;可以被任一队列的maxRunningApps元素覆盖
queueMaxAMShareDefault:设置队列的默认AM共享资源限制;可以被任一队列的maxAMShare 元素覆盖
defaultQueueSchedulingPolicy:设置队列的默认调度策略;可以在任一队列中设置schedulingPolicy 进行覆盖该默认值。默认值为“fair”
queuePlacementPolicy:包含一个Rule元素列表用于告诉调度器如何放置app到队列Rule生效顺序与列表中的顺序一致。Rule可以含有参数。
所有Rule接受"create"参数,用于标明该规则是否能够创建新队列."Create"默认值为true;如果设置为false并且Rule要放置app到一个allocations file没有配置的队列,那么继续应用下一个Rule。最后的Rule绝不能执行Continue
specified:app放置到它请求的队列。如果没有请求队列,例如它指定"default",执行continue。如果app请求队列以英文句点开头或者结尾,例如 “.q1” 或者 “q1.” 将会被拒绝
user:app按照提交用户名放置到同名的队列。用户名中的英文句点将会被“_dot_”替换,如对于用户"first.last"的队列名是"first_dot_last"
primaryGroup:app放置到与提交用户primary group同名的队列。用户名中的英文句点将会被“_dot_”替换,如对于组"one.two"的队列名是"one_dot_two"
secondaryGroupExistingQueue:app放置到与提交用户所属的secondary group名称相匹配的队列。
第一个与配置相匹配的secondary group将会被选中。组名中的英文句点会被替换成“_dot_”,例如用户使用“one.two”作为他的secondary groups将会放置到“one_dot_two”队列,如果这个队列存在的话
nestedUserQueue: app放置到根据队列中嵌套规则建议的用户名同名的队列中。
这有些类似于UserRule,在‘nestedUserQueue’规则中不同的是用户队列可以创建在任意父队列下,而'user'规则只能在root队列下创建用户队列。
有一点需要注意,nestedUserQueue 规则只有在嵌入规则返回一个父队列时才会生效。用户可以通过设置 队列的‘type’属性为 ‘parent’ 来配置父队列,或者在队列下至少配置一个叶子
default: app放置到default规则中指定的 ‘queue’属性对应的队列。如果 ‘queue’属性没有指定,app放置到 ‘root.default’ 队列
reject:拒绝app
一个公平调度队列设置的例子如下:
<?xml version="1.0"?>
<allocations>
<queue name="sample_queue">
<minResources>10000 mb,0vcores</minResources> <!--最少资源保证量,设置格式为“X mb, Y vcores”-->
<maxResources>90000 mb,0vcores</maxResources> <!--最多可以使用的资源量-->
<maxRunningApps>50</maxRunningApps> <!--最多同时运行的应用程序数目。通过限制该数目,可防止超量Map Task同时运行时产生的中间输出结果撑爆磁盘-->
<maxAMShare>0.1</maxAMShare>
<weight>2.0</weight>
<schedulingPolicy>fair</schedulingPolicy> <!--队列采用的调度模式,可以是fifo、fair或者drf-->
<queue name="sample_sub_queue"> <!--定义子队列-->
<aclSubmitApps>charlie</aclSubmitApps>
<minResources>5000 mb,0vcores</minResources>
</queue>
</queue>
<queueMaxAMShareDefault>0.5</queueMaxAMShareDefault>
<!—- Queue 'secondary_group_queueue' is a parent queue and may have user queues under it -->
<queue name="secondary_group_queue" type="parent">
<weight>3.0</weight>
</queue>
<user name="sample_user"> <!--为单个用户设置最多同时运行应用程序的数目-->
<maxRunningApps>30</maxRunningApps>
</user>
<userMaxAppsDefault>5</userMaxAppsDefault>
<queuePlacementPolicy>
<rule name="specified" />
<rule name="primaryGroup" create="false" />
<rule name="nestedUserQueue">
<rule name="secondaryGroupExistingQueue" create="false" />
</rule>
<rule name="default" queue="sample_queue"/>
</queuePlacementPolicy>
</allocations>
公平调度与计算能力调度的区别:
公平调度的单位本质是pool,而计算能力调度的单位本质是queue.由此带来公平调度和计算能力调度在处理调度,资源争夺等等方面的不同.
因为计算能力调度是queue,所以其内部只能是FIFO的方式调度,虽然可以设置优先级,但是也不可以发生抢占,所以争夺形式为弹性队列暂时借用其它队列资源(也必须始终保持FIFO).
而公平调度的本质是pool(通常就是用户),所以其调度方式既可以是权重也可以是FIFO.而在得不到最小资源的情况下可以杀死其它并行的任务来抢夺资源(此时其它任务不是失败而是阻塞等待重启)