本文档描述FairScheduler,一个允许YARN应用程序公平共享集群资源的调度插件。
概述
公平调度是一个分配资源给所有application的方法,平均来看,是随着时间的进展平等分享资源的。下一代Hadoop可调度多资源类型。默认的,FairScheduler只基于内存的公平调度策略。它可以配置为包括内存和cpu的调度,采用Ghodsi等开发的主资源公平算法。当只有一个application运行时,该application使用整个集群。当其他应用程序提交之后,释放出来的资源分配给新的application,所以每个application最终会得到大致相同量的资源。不像默认的hadoop调度器,它由一个应用程序的队列组成,这让短应用在合理的时间内结束而不是长时间存活引起系统调度饥饿。它还是在一定数量用户间共享集群的一个合理方法。最后,公平分享也可以与应用程序优先级一起工作——优先级用作决定每个应用程序应该获得的总资源的比例的权重。
调度器组织应用程序进入“队列”,并公平共享这些队列间的资源。默认的,所有用户共享一个叫做“default”的队列。如果一个应用程序在容器资源请求中列出了一个队列,那么这个请求将被提交到该队列。通过配置也可以基于包含在请求中的用户名来分配队列。对于每一个队列,通过一个调度策略用于在运行的应用程序中共享资源。默认是基于内存的公平共享,但是也可以配置FIFO和多资源的DRF。队列可以编排成层级结构以便拆分资源,并且可以通过权重配置分享集群特定比例的资源。
另外为了提供公平共享,Fairscheduler允许为队列分配最小共享份额,这对确保特定用户、组、产品应用始终获得足够的资源非常有用。当队列包含应用时,它至少要获得共享最小份额,但是当队列不需要它完全保证的份额时,多出的部分拆分给其他运行中的应用程序。这就让调度器既保证了队列的容量,又可以在这些队列不包含应用程序时高效的利用资源。
FairScheduler默认让所有app运行,但是它也能通过配置文件限制每个用户、队列的运行app的数量。这对用户一次必须提交几百app或者想要提升性能(如果一次运行过多app会引起创建过多的中间数据,或者过多的上下文切换)时很有用。限制app不会引起后续的提交app失败,只会在调度器的队列中等待,直到某些用户较早的app结束。
Fair Scheduler支持层级队列。所有的队列都从属于一个叫做“root”的队列。可用的资源采用典型的公平调度方式在root队列的子队列中分布。然后,子队列将分配给他们的资源采用相同的方式分布到他们的子队列中。App只在叶子队列上调度。通过在分配文件中放置队列作为他们双亲的子元素,可以将队列指定为其他队列的子队列。
队列的名称已其双亲的名称作为开头,用句点(".")作为分隔符.所以root队列下的名为"queue1"的队列会被称为“root.queue1”,位于“parent1”队列下的“queue2”队列会被称为"root.parent1.queue2".当提到队列时,名称中的root部分是可选的,所以queue1可以被称为"queue1",queue2可以被称为“parent1.queue2”.
另外,FairScheduler允许为不同的队列设置不同的个性化策略,允许采用用户想要的方式共享队列的资源。个性化策略可以通过继承 org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.SchedulingPolicy来构建。 内置的FifoPolicy, FairSharePolicy (默认的), 以及DominantResourceFairnessPolicy策略可以方便的使用。在原始的(MR1)FairScheduler中存在的特定插件现在还不支持。其中,是使用自定义的策略在特定应用程序上调整优先级“提升”。
自动放置应用程序到队列
Fairscheduler允许管理员配置策略,将提交的应用程序放置到相应的队列。放置依赖于提交的用户和组,以及应用程序传过来的申请中的队列信息。一个策略由一组规则组成,这些规则对进来的应用程序进行一系列的分类。每个规则要么放置应用程序到一个队列,或者拒绝它,又或者继续交由下一个规则。关于如何配置这些策略可以参考下面分配文件格式。
要使用FairScheduler首先要在yarn-site.xml中指定相应的调度器class。
<property>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
</property>
定制化FairScheduler通常会引起两个文件的变更。首先调度器层面的选项可以通过在配置目录下yar-site.xml文件中增加配置项进行设置。其次,在大多数情况下用户将想要创建一个分配文件表明存在哪些队列,以及它们的相应权重和容量。这个分配文件每10秒重载一次,因此允许在运行时进行修改。
yarn.scheduler.fair.allocation.file | 分配文件的路径。分配文件是一个xml,描述队列以及它们的属性,补充特定的默认策略。这个文件必须是下一节描述的xml格式。如果指定了一个相对路径,将会在classpath下搜索这个文件(通常在hadoop的conf目录下)。默认是fair-scheduler.xml. |
---|---|
yarn.scheduler.fair.user-as-default-queue | 在队列名未指定的情况下,是否使用用户名作为分配的默认队列名。如果本项设置为“false”或者未设置,所有的作业拥有一个共享的默认队列,名为“default”。默认值为true.如果一个队列的放置策略已经在分配文件中指定,本属性将会被忽略。 |
yarn.scheduler.fair.preemption | 是否使用抢占。默认是false。 |
yarn.scheduler.fair.preemption.cluster-utilization-threshold | 启动抢占后的资源利用率阈值。利用率是计算所有资源中容量使用的最大比率。 默认值是0.8f。 |
yarn.scheduler.fair.sizebasedweight | 是否基于独立app的大小为其分配共享资源,而不是不顾所有app的大小都分配相等的共享资源。当设置为true时,app的权重是app的所有请求内存的自然对数加权,除以以2为底的自然对数。默认值为false. |
yarn.scheduler.fair.assignmultiple | 是否允许一次心跳中进行多容器分配。默认是false. |
yarn.scheduler.fair.max.assign | 如果assignmultiple 设置为true,一次心跳最多分配的容器数量。默认为-1,表示不限制。 |
yarn.scheduler.fair.locality.threshold.node | 对于请求在特定节点的容器的apps,自从最后一次容器分配之后等待接受配置到其他节点的调度机会次数。表达式为0到1之间的浮点数,作为集群大小的因子,是错过的调度机会。默认值为-1.0意思是不错过任何调度机会。当应用程序请求某个节点上资源时,它可以接受的可跳过的最大资源调度机会。当按照分配策略,可将一个节点上的资源分配给某个应用程序时,如果该节点不是应用程序期望的节点,可选择跳过该分配机会暂时将资源分配给其他应用程序,直到出现满足该应用程序需的节点资源出现。通常而言,一次心跳代表一次调度机会,而该参数则表示跳过调度机会占节点总数的比例,默认情况下,该值为-1.0,表示不跳过任何调度机会。 |
yarn.scheduler.fair.locality.threshold.rack | 对于请求在特定机架的容器的apps,自从最后一次容器分配等待接受配置到其他机架的调度机会数量。表达式为0到1之间的浮点数,作为集群大小的因子,是错过的调度机会。默认值为-1.0意思是不错过任何调度机会。 |
yarn.scheduler.fair.allow-undeclared-pools | 如果设置为true,application提交时可以创建新的队列,要么是因为application指定了队列,或者是按照user-as-default-queue放置到相应队列。如果设置为false,任何时间一个app要放置到一个未在分配文件中指定的队列,都将被放置到“default”队列。默认是true。如果一个队列放置策略已经在分配文件中指定,本属性将会被忽略。 |
yarn.scheduler.fair.update-interval-ms | 默认值500ms,锁住调度器重新进行计算作业所需资源的间隔 |
分配文件必须是XML格式。格式包含5类元素:
以下给出 allocation file的一个样例:
<?xml version="1.0"?>
<allocations>
<queue name="sample_queue">
<minResources>10000 mb,0vcores</minResources>
<maxResources>90000 mb,0vcores</maxResources>
<maxRunningApps>50</maxRunningApps>
<maxAMShare>0.1</maxAMShare>
<weight>2.0</weight>
<schedulingPolicy>fair</schedulingPolicy>
<queue name="sample_sub_queue">
<aclSubmitApps>charlie</aclSubmitApps>
<minResources>5000 mb,0vcores</minResources>
</queue>
</queue>
<queueMaxAMShareDefault>0.5</queueMaxAMShareDefault>
<!-- Queue 'secondary_group_queue' 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>
为了保持与原始的FairScheduler的向后兼容,“queue”元素可以用名为“pool”的元素替代.
访问控制列表(ACLs)允许管理员控制谁能对特定队列执行操作。这些用户通过aclSubmitApps 和aclAdministerApps属性配置,可以设置在每个队列上。当前唯一支持的管理性操作就是杀死app。任何能够管理管理的人也都可以向该队列提交app.这些属性的值像 “user1,user2 group1,group2” 或者“ group1,group2”的格式。如果用户或者组是在队列的ACLs中或者在这个队列的任意祖先的ACLs中,那么他对该队列的操作是被允许的。所以,如果queue2 在queue1内部,并且user1 在queue1的ACL中,user2 在queue2的ACL中,那么两个用户都可以向queue2提交app.
备注:分隔符是空格。要只是指定ACL组,该值需要以空格开头.
root队列的ACLs默认是"*",因为ACLs是向下传递的,意思是每个用户都可以对每一个队列提交和杀死App。要启动严格的方访问,修改root队列的ACL为除"*"之外的其他值.
Fair Scheduler通过一些机制提供运行时的管理功能:
通过编辑allocation file可以在运行时完成修改最小共享,资源限制,权重,超时抢占以及队列调度策略等。调度器会每个10-15秒重载修改后的该配置文件.
当前应用、队列以及公平共享都可以通过ResourceManager的web UI查看,地址在http://*ResourceManager URL*/cluster/scheduler。
在web UI上可以看到每个队列的以下字段:
Fair Scheduler 支持移动一个运行中的应用程序到另外一个队列。这个可以用于移动一个重要的应用程序到较高优先级队列,或者移动一个不重要的应用程序到一个较低优先级的队列。通过运行 yarn application -movetoqueue appID -queue targetQueueName可以移动运行中的应用程序。
当应用程序移动到一个队列,出于公平考虑,它的现存的分配计算会变成新队列的资源分配。如果加入被移动的应用程序的资源超出目标队列的maxRunningApps 或者maxResources 限制,本次移动将会失败。