理想状况下,咱们应用对Yarn资源的请求应该马上获得知足,但现实状况资源每每是有限的,特别是在一个很繁忙的集群,一个应用资源的请求常常须要等待一段时间才能的到相应的资源。在Yarn中,负责给应用分配资源的就是Scheduler。其实调度自己就是一个难题,很难找到一个完美的策略能够解决全部的应用场景。为此,Yarn提供了多种调度器和可配置的策略供咱们选择。YARN架构以下:算法
FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求知足后再给下一个分配,以此类推。FIFO Scheduler是最简单也是最容易理解的调度器,也不须要任何配置,但它并不适用于共享集群。大的应用可能会占用全部集群资源,这就致使其它应用被阻塞。在共享集群中,更适合采用Capacity Scheduler或Fair Scheduler,这两个调度器都容许大任务和小任务在提交的同时得到必定的系统资源。下面“Yarn调度器对比图”展现了这几个调度器的区别,从图中能够看出,在FIFO 调度器中,小任务会被大任务阻塞。apache
yarn-site.xml中默认配置的资源调度器。而对于Capacity调度器,有一个专门的队列用来运行小任务,可是为小任务专门设置一个队列会预先占用必定的集群资源,这就致使大任务的执行时间会落后于使用FIFO调度器时的时间。用这个资源调度器,就能够配置yarn资源队列,这个后面后介绍用到。网络
Fair调度器的设计目标是为全部的应用分配公平的资源(对公平的定义能够经过参数来设置)。在上面的“Yarn调度器对比图”展现了一个队列中两个应用的公平调度;固然,公平调度在也能够在多个队列间工做。举个例子,假设有两个用户A和B,他们分别拥有一个队列。当A启动一个job而B没有任务时,A会得到所有集群资源;当B启动一个job后,A的job会继续运行,不过一下子以后两个任务会各自得到一半的集群资源。若是此时B再启动第二个job而且其它job还在运行,则它将会和B的第一个job共享B这个队列的资源,也就是B的两个job会用于四分之一的集群资源,而A的job仍然用于集群一半的资源,结果就是资源最终在两个用户之间平等的共享。在Fair调度器中,咱们不须要预先占用必定的系统资源,Fair调度器会为全部运行的job动态的调整系统资源。当第一个大job提交时,只有这一个job在运行,此时它得到了全部集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
a) 公平调度器,就是可以共享整个集群的资源
b) 不用预先占用资源,每个做业都是共享的
c) 每当提交一个做业的时候,就会占用整个资源。若是再提交一个做业,那么第一个做业就会分给第二个做业一部分资源,第一个做业也就释放一部分资源。再提交其余的做业时,也同理。。。。也就是说每个做业进来,都有机会获取资源。架构
yarn资源调度器是在yarn-site.xml中配置app
Fair Scheduler的配置选项包括两部分:负载均衡
yarn-site.xml框架
<!– scheduler start –> <property> <name>yarn.resourcemanager.scheduler.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value> <description>配置Yarn使用的调度器插件类名;Fair Scheduler对应的是:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</description> </property> <property> <name>yarn.scheduler.fair.allocation.file</name> <value>/etc/hadoop/conf/fair-scheduler.xml</value> <description>配置资源池以及其属性配额的XML文件路径(本地路径)</description> </property> <property> <name>yarn.scheduler.fair.preemption</name> <value>true</value> <description>开启资源抢占,default is True</description> </property> <property> <name>yarn.scheduler.fair.user-as-default-queue</name> <value>true</value> <description>设置成true,当任务中未指定资源池的时候,将以用户名做为资源池名。这个配置就实现了根据用户名自动分配资源池。default is True</description> </property> <property> <name>yarn.scheduler.fair.allow-undeclared-pools</name> <value>false</value> <description>是否容许建立未定义的资源池。若是设置成true,yarn将会自动建立任务中指定的未定义过的资源池。设置成false以后,任务中指定的未定义的资源池将无效,该任务会被分配到default资源池中。,default is True</description> </property> <!– scheduler end –>
假设在生产环境Yarn中,总共有四类用户须要使用集群,production、spark、default、streaming。为了使其提交的任务不受影响,咱们在Yarn上规划配置了四个资源池,分别为production,spark,default,streaming。并根据实际业务状况,为每一个资源池分配了相应的资源及优先级等,default用于开发测试目的.分布式
ResourceManager上fair-scheduler.xml配置以下:oop
<?xml version="1.0"?> <allocations> <queue name="root"> <aclSubmitApps></aclSubmitApps> <aclAdministerApps></aclAdministerApps> <queue name="production"> <minResources>8192mb,8vcores</minResources> <maxResources>419840mb,125vcores</maxResources> <maxRunningApps>60</maxRunningApps> <schedulingMode>fair</schedulingMode> <weight>7.5</weight> <aclSubmitApps>*</aclSubmitApps> <aclAdministerApps>production</aclAdministerApps> </queue> <queue name="spark"> <minResources>8192mb,8vcores</minResources> <maxResources>376480mb,110vcores</maxResources> <maxRunningApps>50</maxRunningApps> <schedulingMode>fair</schedulingMode> <weight>1</weight> <aclSubmitApps>*</aclSubmitApps> <aclAdministerApps>spark</aclAdministerApps> </queue> <queue name="default"> <minResources>8192mb,8vcores</minResources> <maxResources>202400mb,20vcores</maxResources> <maxRunningApps>20</maxRunningApps> <schedulingMode>FIFO</schedulingMode> <weight>0.5</weight> <aclSubmitApps>*</aclSubmitApps> <aclAdministerApps>*</aclAdministerApps> </queue> <queue name="streaming"> <minResources>8192mb,8vcores</minResources> <maxResources>69120mb,16vcores</maxResources> <maxRunningApps>20</maxRunningApps> <schedulingMode>fair</schedulingMode> <aclSubmitApps>*</aclSubmitApps> <weight>1</weight> <aclAdministerApps>streaming</aclAdministerApps> </queue> </queue> <user name="production"> <!-- 对于特定用户的配置:production最多能够同时运行的任务 --> <maxRunningApps>100</maxRunningApps> </user> <user name="default"> <!-- 对于默认用户配置最多能够同时运行的任务 --> <maxRunningApps>10</maxRunningApps> </user> <!-- users max running apps --> <userMaxAppsDefault>50</userMaxAppsDefault> <!--默认的用户最多能够同时运行的任务 --> <queuePlacementPolicy> <rule name="specified"/> <rule name="primaryGroup" create="false" /> <rule name="secondaryGroupExistingQueue" create="false" /> <rule name="default" queue="default"/> </queuePlacementPolicy> </allocations>
参数介绍:测试
管理员也可为单个用户添加maxRunningJobs属性限制其最多同时运行的应用程序数目。此外,管理员也可经过如下参数设置以上属性的默认值:
这样,每一个用户组下的用户提交任务时候,会到相应的资源池中,而不影响其余业务。队列的层次是经过嵌套<queue>元素实现的。全部的队列都是root队列的孩子,即便没有配到<root>元素里。Fair调度器中的队列有一个权重属性(这个权重就是对公平的定义),并把这个属性做为公平调度的依据。在这个例子中,当调度器分配集群7.5,1,1,0.5资源给production,spark,streaming,default时便视做公平,这里的权重并非百分比。注意,对于在没有配置文件时按用户自动建立的队列,它们仍有权重而且权重值为1。每一个队列内部仍能够有不一样的调度策略。队列的默认调度策略能够经过顶级元素<defaultQueueSchedulingPolicy>进行配置,若是没有配置,默认采用公平调度。尽管是Fair调度器,其仍支持在队列级别进行FIFO调度。每一个队列的调度策略能够被其内部的<schedulingPolicy> 元素覆盖,在上面这个例子中,default队列就被指定采用fifo进行调度,因此,对于提交到default队列的任务就能够按照FIFO规则顺序的执行了。须要注意,spark,production,streaming,default之间的调度仍然是公平调度。每一个队列可配置最大、最小资源占用数和最大可运行的应用的数量。
Fair调度器采用了一套基于规则的系统来肯定应用应该放到哪一个队列。在上面的例子中,<queuePlacementPolicy> 元素定义了一个规则列表,其中的每一个规则会被逐个尝试直到匹配成功。例如,上例第一个规则specified,则会把应用放到它指定的队列中,若这个应用没有指定队列名或队列名不存在,则说明不匹配这个规则,而后尝试下一个规则。primaryGroup规则会尝试把应用放在以用户所在的Unix组名命名的队列中,若是没有这个队列,不建立队列转而尝试下一个规则。当前面全部规则不知足时,则触发default规则,把应用放在default队列中。
固然,咱们能够不配置queuePlacementPolicy
规则,调度器则默认采用以下规则:
<queuePlacementPolicy> <rule name="specified" /> <rule name="user" /> </queuePlacementPolicy>
上面规则意思是除非队列被准确的定义,不然会以用户名为队列名建立队列。还有一个简单的配置策略可使得全部的应用放入同一个队列(default),这样就可让全部应用之间平等共享集群而不是在用户之间。这个配置的定义以下:
<queuePlacementPolicy> <rule name="default" /> </queuePlacementPolicy>
实现上面功能咱们还能够不使用配置文件,直接设置yarn.scheduler.fair.user-as-default-queue=false,这样应用便会被放入default 队列,而不是各个用户名队列。另外,咱们还能够设置yarn.scheduler.fair.allow-undeclared-pools=false,这样用户就没法建立队列了。
当一个job提交到一个繁忙集群中的空队列时,job并不会立刻执行,而是阻塞直到正在运行的job释放系统资源。为了使提交job的执行时间更具预测性(能够设置等待的超时时间),Fair调度器支持抢占。抢占就是容许调度器杀掉占用超过其应占份额资源队列的containers,这些containers资源即可被分配到应该享有这些份额资源的队列中。须要注意抢占会下降集群的执行效率,由于被终止的containers须要被从新执行。能够经过设置一个全局的参数yarn.scheduler.fair.preemption=true来启用抢占功能。此外,还有两个参数用来控制抢占的过时时间(这两个参数默认没有配置,须要至少配置一个来容许抢占Container):
minSharePreemptionTimeout
fairSharePreemptionTimeout
若是队列在minimum share preemption timeout指定的时间内未得到最小的资源保障,调度器就会抢占containers。咱们能够经过配置文件中的顶级元素<defaultMinSharePreemptionTimeout>为全部队列配置这个超时时间;咱们还能够在<queue>元素内配置<minSharePreemptionTimeout>元素来为某个队列指定超时时间。
与之相似,若是队列在fair share preemption timeout指定时间内未得到平等的资源的一半(这个比例能够配置),调度器则会进行抢占containers。这个超时时间能够经过顶级元素<defaultFairSharePreemptionTimeout>和元素级元素<fairSharePreemptionTimeout>分别配置全部队列和某个队列的超时时间。上面提到的比例能够经过<defaultFairSharePreemptionThreshold>(配置全部队列)和<fairSharePreemptionThreshold>(配置某个队列)进行配置,默认是0.5。
须要注意的是,全部客户端提交任务的用户和用户组的对应关系,须要维护在ResourceManager上,ResourceManager在分配资源池时候,是从ResourceManager上读取用户和用户组的对应关系的,不然就会被分配到default资源池。在日志中出现”UserGroupInformation: No groups available for user”相似的警告。而客户端机器上的用户对应的用户组可有可无。
每次在ResourceManager上新增用户或者调整资源池配额后,须要执行下面的命令刷新使其生效.
yarn rmadmin -refreshQueues
yarn rmadmin -refreshUserToGroupsMappings
动态更新只支持修改资源池配额,若是是新增或减小资源池,则须要重启Yarn集群.
Fair Scheduer各资源池配置及使用状况,在ResourceManager的WEB监控页面上也能够看到: http://ResourceManagerHost:8088/cluster/scheduler
Reference:
1.Hadoop多用户资源管理–Fair Scheduler介绍与配置
hadoop2.7默认使用的是Capacity Scheduler容量调度器
yarn-site.xml
<property> <name>yarn.resourcemanager.scheduler.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.capacity.CapacityScheduler</value> </property>
Capacity 调度器容许多个组织共享整个集群,每一个组织能够得到集群的一部分计算能力。经过为每一个组织分配专门的队列,而后再为每一个队列分配必定的集群资源,这样整个集群就能够经过设置多个队列的方式给多个组织提供服务了。除此以外,队列内部又能够垂直划分,这样一个组织内部的多个成员就能够共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
一个job可能使用不了整个队列的资源。然而若是这个队列中运行多个job,若是这个队列的资源够用,那么就分配给这些job,若是这个队列的资源不够用了呢?其实Capacity调度器仍可能分配额外的资源给这个队列,这就是“弹性队列”(queue elasticity)的概念。
在正常的操做中,Capacity调度器不会强制释放Container,当一个队列资源不够用时,这个队列只能得到其它队列释放后的Container资源。固然,咱们能够为队列设置一个最大资源使用量,以避免这个队列过多的占用空闲资源,致使其它队列没法使用这些空闲资源,这就是”弹性队列”须要权衡的地方。
假设咱们有以下层次的队列:
root
├── prod
└── dev
├── eng
└── science
下面是一个简单的Capacity调度器的配置文件,文件名为capacity-scheduler.xml
。在这个配置中,在root队列下面定义了两个子队列prod
和dev
,分别占40%和60%的容量。须要注意,一个队列的配置是经过属性yarn.sheduler.capacity.<queue-path>.<sub-property>
指定的,<queue-path>
表明的是队列的继承树,如root.prod
队列,<sub-property>
通常指capacity
和maximum-capacity
。
咱们能够看到,dev队列又被分红了eng和science两个相同容量的子队列。dev的maximum-capacity属性被设置成了75%,因此即便prod队列彻底空闲dev也不会占用所有集群资源,也就是说,prod队列仍有25%的可用资源用来应急。咱们注意到,eng和science两个队列没有设置maximum-capacity属性,也就是说eng或science队列中的job可能会用到整个dev队列的全部资源(最多为集群的75%)。而相似的,prod因为没有设置maximum-capacity属性,它有可能会占用集群所有资源。Capacity容器除了能够配置队列及其容量外,咱们还能够配置一个用户或应用能够分配的最大资源数量、能够同时运行多少应用、队列的ACL认证等。
关于队列的设置,这取决于咱们具体的应用。好比,在MapReduce中,咱们能够经过mapreduce.job.queuename属性指定要用的队列。若是队列不存在,咱们在提交任务时就会收到错误。若是咱们没有定义任何队列,全部的应用将会放在一个default队列中。
注意:对于Capacity调度器,咱们的队列名必须是队列树中的最后一部分,若是咱们使用队列树则不会被识别。好比,在上面配置中,咱们使用prod和eng做为队列名是能够的,可是若是咱们用root.dev.eng或者dev.eng是无效的。
yarn-site.xml
<property> <name>yarn.resourcemanager.scheduler.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.fifo.FifoScheduler</value> </property>