Hadoop FairScheduler
目标
本文档描述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>
配置
yarn-site.xml中可以被放置的属性
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,锁住调度器重新进行计算作业所需资源的间隔 |
allocation file格式
分配文件必须是xml格式。格式包含5类元素:
-
队列元素:描述队列。队列元素可以设定一个可选的属性‘type’,当它设置为‘parent’时表示它是一个父队列。当我们想创建一个父队列但是不想配置任何子队列时可以采用这种方式。每个队列元素可以包含下面的属性:
-
- minresources: 队列有权享有的最小资源,采用"x mb, y vcores”"的形式。对于单一资源公平策略,vcores的值将被忽略。如果一个队列的最小共享未能得到满足,那么它将会在相同parent下其他队列之前获得可用资源。在单一资源公平策略下,一个队列如果它的内存使用量低于最小内存值则认为是未满足的。在drf策略下,如果一个队列的主资源是低于最小共享的话则认为是未满足的。如果有多个队列未满足的情况,资源分配给相关资源使用量和最小值之间比率最小的队列。注意一点情况,有可能一个队列处于最小资源之下,但是在它提交application时不会立刻达到最小资源,因为已经在运行的job会使用这些资源。
- maxresources: 一个队列允许的最大资源,采用“x mb, y vcores”的形式。对于单一资源公平策略,vcores的值会被忽略。一个队列永远不会分配资源总量超过这个限制。
- maxrunningapps: 限制队列一次运行的apps数量。
- maxamshare:限制队列用于运行application master的资源比例。这个属性只能用于叶子队列。比如,如果设置为1.0f,那么在这个队列的ams可以占用100%的内存和cpu的公平共享。这个值为-1.0f将会禁用该特性并且amshare不会进行校验。默认值是0.5f。
- weight: 与其他队列非比例的分享集群。权重默认是1,权重是2的队列将会收到接近默认权重2倍的资源。
- schedulingpolicy:任一队列都可以设置调度策略。允许的值包括“fifo”,“fair”,“drf”或者其他任何继承org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.schedulingpolicy的类。默认是“fair”。如果为"fifo",提交时间较早的apps优先分配容器,但是如果集群在满足较早的apps请求之后剩余足够的空间,提交较晚的apps可能并发运行。
- aclsubmitapps:可以提交apps到队列的用户或者组的列表。要获得更多信息可以参考下面的acls部分,关于列表的格式和acls如何发挥作用。
- acladministerapps:可以管理队列的用户或者组列表。当前唯一的管理动作就是杀死应用程序。要获得更多信息可以参考下面的acls部分,关于列表的格式和acls如何发挥作用。
- minsharepreemptiontimeout:队列处在最小共享之下,在尝试抢占其他队列的资源之前的秒数。如果不设置,队列将会总其父队列继承这个值。
- fairsharepreemptiontimeout:队列处在最小公平共享阈值之下,在尝试抢占其他队列的资源之前的秒数。如果不设置,队列将会总其父队列继承这个值。
- fairsharepreemptionthreshold:队列的公平共享抢占阈值。如果队列等待fairsharepreemptiontimeout之后没有接收到fairsharepreemptionthreshold*fairshare的资源,它被允许从其他队列抢占资源。如果不设置,队列将会总其父队列继承这个值。
-
user elements:设置对单独用户行为的管理。它们可以包含单一属性:maxrunningapps,对特定用户可以运行的apps的数量限制。
-
a usermaxappsdefault element:设置任意用户(没有特定限制的用户)运行app的默认最大数量限制。
-
a defaultfairsharepreemptiontimeout element:设置root队列的公平共享抢占的默认超时时间;可以被root队列下的fairsharepreemptiontimeout 设置覆盖。
-
a defaultminsharepreemptiontimeout element:设置root队列的默认最小共享抢占超时时间;可以被root队列下minsharepreemptiontimeout覆盖。
-
a defaultfairsharepreemptionthreshold element:设置root队列的公平共享抢占的默认阈值;可以被root队列下的fairsharepreemptionthreshold 覆盖。
-
a queuemaxappsdefault element:设置队列的默认运行app数量限制;可以被任一队列的maxrunningapps元素覆盖。
-
a queuemaxamsharedefault element:设置队列的默认am共享资源限制;可以被任一队列的maxamshare 元素覆盖。
-
a defaultqueueschedulingpolicy element:设置队列的默认调度策略;可以在任一队列中设置schedulingpolicy 进行覆盖该默认值。默认值为“fair”。
-
a queueplacementpolicy element:包含一个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.
以下给出 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”的元素替代.
队列访问控制列表
备注:分隔符是空格。要只是指定acl组,该值需要以空格开头.
root队列的acls默认是"*",因为acls是向下传递的,意思是每个用户都可以对每一个队列提交和杀死app。要启动严格的方访问,修改root队列的acl为除"*"之外的其他值.
管理
fair scheduler通过一些机制提供运行时的管理功能:
运行时修改配置
通过编辑allocation file可以在运行时完成修改最小共享,资源限制,权重,超时抢占以及队列调度策略等。调度器会每个10-15秒重载修改后的该配置文件.
通过web ui进行监控
当前应用、队列以及公平共享都可以通过resourcemanager的web ui查看,地址在http://*resourcemanager url*/cluster/scheduler。
在web ui上可以看到每个队列的以下字段:
-
used resources-队列已经分配的容器的资源之和。
-
num active applications-队列中已经接受到至少一个容器的应用程序数量。
-
num pending applications-队列中还没有接受任何一个容器的应用程序的数量。
-
min resources-配置的授予队列的最小资源。
-
max resources - 配置的队列允许的最大资源.
-
instantaneous fair share - 队列的资源的瞬时公平共享。这些共享只考虑活动的队列(那些有运行中程序的),而且被调度决策所使用。当其他队列没有使用某些资源时,队列可以被分配到超过他shares的资源。一个队列的资源消费处在或者低于它的瞬时公平份额将不会有容器被抢占。
-
steady fair share-队列的固定公平份额,无论这些队列是否活跃。他们很少被计算和修改,除非配置或者容量发生变化。他们意思是提供资源可视化。
队列间移动应用程序
fair scheduler 支持移动一个运行中的应用程序到另外一个队列。这个可以用于移动一个重要的应用程序到较高优先级队列,或者移动一个不重要的应用程序到一个较低优先级的队列。通过运行 yarn application -movetoqueue appid -queue targetqueuename可以移动运行中的应用程序。
当应用程序移动到一个队列,出于公平考虑,它的现存的分配计算会变成新队列的资源分配。如果加入被移动的应用程序的资源超出目标队列的maxrunningapps 或者maxresources 限制,本次移动将会失败。