关于YARN

一、YARN应用运行机制

模块工作职能(主要架构)

  • ResourceManager(RM)

    RM是一个全局的资源管理器,负责对各NM上的资源进行统一管理和调度,为AM分配空闲的Container运行并监控其运行状态。对AM申请的资源请求分配相应的空闲Container。主要由两个组件构成:调度器(Scheduler)和应用程序管理器(Applications Manager)。

  • 调度器(Scheduler)

    调度器根据容量、队列等限制条件(如每个队列分配一定的资源,最多执行一定数量的作业等),将系统中的资源分配给各个正在运行的应用程序。调度器仅根据各个应用程序的资源需求进行资源分配,而资源分配单位是Container,从而限定每个任务使用的资源量。Scheduler不负责监控或者跟踪应用程序的状态,也不负责任务因为各种原因而需要的重启(由ApplicationMaster负责)。总之,调度器根据应用程序的资源要求,以及集群机器的资源情况,为用程序分配封装在Container中的资源。调度器是可插拔的,例如CapacityScheduler、FairScheduler。(PS:在实际应用中,只需要简单配置即可)

  • 应用程序管理器(Applications Manager)

    应用程序管理器负责管理整个系统中所有应用程序,包括应用程序提交、与调度器协商资源以启动AM、监控AM运行状态并在失败时重新启动等,跟踪分给的Container的进度、状态也是其职责。

  • NodeManager(NM)

    NM是每个节点上的资源和任务管理器。它会定时地向RM汇报本节点上的资源使用情况和各个Container的运行状态;同时会接收并处理来自AM的Container 启动/停止等请求。

  • ApplicationMaster(AM)

    用户提交的应用程序均包含一个AM,负责应用的监控,跟踪应用执行状态,重启失败任务等。ApplicationMaster是应用框架,它负责向ResourceManager协调资源,并且与NodeManager协同工作完成Task的执行和监控。MapReduce就是原生支持的一种框架,可以在YARN上运行Mapreduce作业。有很多分布式应用都开发了对应的应用程序框架,用于在YARN上运行任务,例如Spark,Storm等。如果需要,我们也可以自己写一个符合规范的YARN application。

    RM只负责监控AM,在AM运行失败时候启动它,RM并不负责AM内部任务的容错,这由AM自己来完成。

  • Container

    是YARN中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等,当AM向RM申请资源时,RM为AM返回的资源便是用Container 表示的。YARN会为每个任务分配一个Container且该任务只能使用该Container中描述的资源。

    Container不同于MRv1中的slot,它是一个动态资源划分单位,是根据应用程序的需求动态生成的。不会出现集群资源闲置的尴尬情况.

YARN应用的运行

work
  1. 首先客户端请求RM,运行一个application master
  1. RM找到可以在容器中启动application master的NM,在NM启动容器,运行application master

  2. 容器通过心跳机制向RM请求运行资源(内存和CPU)

  1. application master运行起来之后需要做什么依赖于客户端传递的应用

    a. 简单地运算后直接返回结果给客户端

    b. 请求更多容器进行分布式计算(MapReduce on YARN)

二、Yarn与MapReduce 1相比

MapReduce1

  • JobTracker的职责:
    • Job调度(将Tasks与TaskTrackers匹配)
    • Task进程监控(keeping track of tasks, restarting failed orslow tasks, and doing task bookkeeping, such as maintaining counter totals)
    • 存储已经完成的job的历史信息
  • TaskTracker的职责:运行tasks,向JobTracker发送进展报告

YARN的基本思想是将JobTracker的两个主要功能(资源管理和作业调度/监控)分离,主要方法是创建一个全局的ResourceManager(RM)和若干个针对应用程序的ApplicationMaster(AM)。这里的应用程序是指传统的MapReduce作业或作业的DAG。

YARN 分层结构的本质是 ResourceManager。这个实体控制整个集群并管理应用程序向基础计算资源的分配。

ResourceManager将各个资源部分(计算、内存、带宽等)精心安排给基础 NodeManager。ResourceManager 还与 ApplicationMaster 一起分配资源,与 NodeManager一起启动和监视它们的基础应用程序。

在此上下文中,ApplicationMaster 承担了以前的 TaskTracker 的一些角色,ResourceManager 承担了 JobTracker 的角色。

ApplicationMaster 管理着在 YARN 内运行的应用程序的每个实例。ApplicationMaster 负责协调来自 ResourceManager 的资源,并通过 NodeManager 监视容器的执行和资源使用(CPU、内存等的资源分配)。

MapReduce 1 Yarn
Jobtracker 资源管理器ResourceManager、Application Master、时间轴服务器TimeLine Server
Trasktracker 节点管理器NodeManager
Slot 容器Container

相比于MapReduce 1,YARN的好处包括以下几方面:

可扩展性(Scalability)

利用资源管理器和applicatoin master分离的架构优点分离管理资源和处理job的功能;job tracker则同时负责这两项,还要存储已完成作业历史,更包含了timeline server的功能,不利于扩展

可用性(Availability)

jobtracker多功能导致复杂的内存状态,难以实现高可用;YARN分而治之,先实现RM的高可用(多个RM),再实现application master的高可用(其他NM上运行相同job)

利用率(Utilization)

每个tasktracker有若干固定长度的slot,可能过大或者过小;每个容器维护一个资源池,按需请求资源

多租户(Multitenancy)

YARN的通用性向除了MapReduce之外其他应用开放了Hadoop,如Spark,Storm等

YARN主要优点

大大减小了 Yarn的ResourceManager资源消耗,并且让监测每一个 Job 子任务 (tasks) 状态的程序分布式化了,更安全、更优美。

在新的 Yarn 中,ApplicationMaster 是一个可变更的部分,用户可以对不同的编程模型写自己的 AppMaster,让更多类型的编程模型能够跑在 Hadoop 集群中。

老的框架中,JobTracker 一个很大的负担就是监控 job 下的 tasks 的运行状况,现在,这个部分就扔给 ApplicationMaster 做了,而 ResourceManager 中有一个模块叫做 ApplicationsManager,它是监测 ApplicationMaster 的运行状况,如果出问题,会将其在其他机器上重启。

Container 是 Yarn 为了将来作资源隔离而提出的一个框架。目前是一个框架,仅仅提供 java 虚拟机内存的隔离,hadoop 团队的设计思路应该后续能支持更多的资源调度和控制。

三、YARN中的调度

理想情况下,YARN应用发出的资源请求应该立刻给予满足。但现实中资源是有限的,在一个繁忙的集群中,一个应用经常需要等待才能得到所需的资源。YARN调度器的工作就是根据既定策略分配资源。YARN中提供了多种调度器和可配置策略供我们选择。hadoop3.2.2默认:

yarn.resourcemanager.scheduler.class org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler

FIFO Scheduler(先入先出调度器)

​ FIFO调度器将应用放置在一个队列中,按照提交的顺序(先进先出)运行应用。首先为队列中第一个应用的请求分配资源,第一个应用的请求被满足后再依次处理队列中的下一个应用服务。FIFO调度器不需要任何配置,但不适合共享集群。因为大的应用会占据集群中的所有资源,每个应用都必须等待直到轮到自己运行。hadoop1.x使用的默认调度器就是FIFO。

FIFO

​ 在集群中,更适合使用Capacity Scheduler(容量调度器)或Fair Scheduler(公平调度器),这样允许长时间运行的作业能及时完成,同时也允许正在进行较小临时查询的用户能够在合理时间内得到返回结果。

Capacity Scheduler(容量调度器)

在使用容量调度器时,一个独立的专门队列保证小作业一提交就可以启动,由于队列容量是为那个队列中的作业所保留的,因此这种策略是以整个集群的利用率为代价的。这意味着与使用FIFO调度器相比,大作业执行的时间要长。

Capacity

Fair Scheduler(公平调度器)

在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的作业之间动态平衡资源。第一个(大)作业启动时,它也是唯一运行的作业,因而获得集群中所有的资源。当第二个(小)作业启动时,它被分配到集群的一半资源,这样每个作业都能公平共享资源。

FAIR

注意,从第二个作业的启动到获得共享资源之间会有时间滞后,因为它必须等待第一个作业使用的容器用完并释放出资源。当小作业结束且不再申请资源后,大作业将回去再次使用全部的集群资源。最终的效果是:既得到了较高的集群利用率,又能保证小作业能及时完成。

四、容量调度器配置

yarn.resourcemanager.scheduler.class:org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler

介绍

​ 容量调度器允许多个组织共享一个Hadoop集群,每个组织可以分配到全部集群资源的一部分。每个组织被配置一个专门的队列,每个队列被配置为可以使用一定的集群资源。队列可以进一步按层次划分,这样每个组织内的不同用户能够共该组织队列所分配的资源。在一个队列内,使用FIFO调度策略对应用进行调度。

​ 如上面那幅图所示,单个作业使用的资源不会超过其队列容量。然而,如果队列中运行多个作业,这个队列的资源不够用且仍有可用的空闲资源,那么容量调度器可能会将空闲的资源分配给这个队列中的作业,尽管会超出队列容量。这就是**“弹性队列”(queue elasticity)**的概念。

​ 正常的操作时,容量调度器不会通过强行中止来抢占容器强(container)。所以,如果一个队列一开始资源够用,然后随着需求增长,资源才开始不够用时,那么这个队列也就只能等其他队列释放容器资源。缓解这种情况的方法是,为队列设置一个最大容量限制,这样这个队列就不会过多侵占其他队列的容量了。这样做是牺牲队列弹性为代价,需要找到一个合理的折中值。

​ 假设一个队列的层次结构如下:

root 
├── prod 
└── dev    
    ├── eng    
    └── science

​ 下面是一个基于上述队列层次的容量调度器配置文件,文件名为capacity-scheduler.xml。在root队列下面定义了两个子队列:proddev,分别占40%和60%的容量。需要注意的是,对特定队列进行配置时,是通过以下形式yarn.sheduler.capacity.<queue-path>.<sub-property>的配置属性进行设置的,其中<queue-path> 表示队列的层次路径(用“.”隔开),例如root.prod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0"?>
<configuration>
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>prod,dev</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.queues</name>
<value>eng,science</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.prod.capacity</name>
<value>40</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.capacity</name>
<value>60</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.maximum-capacity</name>
<value>75</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.eng.capacity</name>
<value>50</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.science.capacity</name>
<value>50</value>
</property>
</configuration>

​ 可以看到,dev队列进一步被划分成eng和science两个容量相等的队列。由于dev队列的最大容量被设置为75%,因此即使prod队列空闲,dev队列也不会占用全部集群资源。换而言之,prod队列能即刻使用的可用资源比例总是能达到25%。由于其他队列没有设置最大容量限制,eng或science中的作业可能会占用dev队列的所有容量(将近75%的集群资源),而prod队列实际则可能会占用全部集群资源。

​ 除了可以配置队列层次和容量,还有些设置是用来控制单个用户或应用能被分配到的最大资源数量、同时运行的应用数量及队列的ACL认证等属性。更多的配置内容可参考https://hadoop.apache.org/docs/r3.2.2/hadoop-yarn/hadoop-yarn-site/CapacityScheduler.html。

​ 补充:关于应用放置在哪个队列,取决于应用本身。例如,在MapReduce中,可以通过设置属性mapreduce.job.queuename来指定要用的队列。如果队列不存在,则在提交时会发送错误。如果不指定队列,那么应用将被放在一个名为default的默认队列中。(队列名应该是队列层次名的最后一部分,如prod和eng是合法的队列名,root.dev.eng和dev.eng作为队列名是无效的。)

特性

  • 层次化的队列设计,这种层次化的队列设计保证了子队列可以使用父队列设置的全部资源。这样通过层次化的管理,更容易合理分配和限制资源的使用。
  • 容量保证,队列上都会设置一个资源的占比,这样可以保证每个队列都不会占用整个集群的资源。
  • 安全,每个队列有严格的访问控制。用户只能向自己的队列里面提交任务,而且不能修改或者访问其他队列的任务。
  • 弹性分配,空闲的资源可以被分配给任何队列。当多个队列出现争用的时候,则会按照比例进行平衡。
  • 多租户租用,通过队列的容量限制,多个用户就可以共享同一个集群,同时保证每个队列分配到自己的容量,提高利用率。
  • 操作性,yarn支持动态修改调整容量、权限等的分配,可以在运行时直接修改。还提供给管理员界面,来显示当前的队列状况。管理员可以在运行时,添加一个队列;但是不能删除一个队列。管理员还可以在运行时暂停某个队列,这样可以保证当前的队列在执行过程中,集群不会接收其他的任务。如果一个队列被设置成了stopped,那么就不能向他或者子队列上提交任务了。
  • 基于资源的调度,协调不同资源需求的应用程序,比如内存、CPU、磁盘等等。

属性

  • 队列属性

    • yarn.scheduler.capacity.<queue-path>.capacity

      它是队列的资源容量占比(百分比)。系统繁忙时,每个队列都应该得到设置的量的资源;当系统空闲时,该队列的资源则可以被其他的队列使用。同一层的所有队列加起来必须是100%。

    • yarn.scheduler.capacity.<queue-path>.maximum-capacity

      队列资源的使用上限。由于系统空闲时,队列可以使用其他的空闲资源,因此最多使用的资源量则是该参数控制。默认是-1,即禁用。

    • yarn.scheduler.capacity.<queue-path>.minimum-user-limit-percent

      每个用户最低资源保障(百分比)。任何时刻,一个队列中每个用户可使用的资源量均有一定的限制。当一个队列中同时运行多个用户的应用程序时中,每个用户的使用资源量在一个最小值和最大值之间浮动,其中,最小值取决于正在运行的应用程序数目,而最大值则由minimum-user-limit-percent决定。比如,假设minimum-user-limit-percent为25。当两个用户向该队列提交应用程序时,每个用户可使用资源量不能超过50%,如果三个用户提交应用程序,则每个用户可使用资源量不能超多33%,如果四个或者更多用户提交应用程序,则每个用户可用资源量不能超过25%。默认是100,即不去做限制。

    • yarn.scheduler.capacity.<queue-path>.user-limit-factor

      每个用户最多使用的队列资源占比,如果设置为50.那么每个用户使用的资源最多就是50%。

  • 运行和提交应用限制

    • yarn.scheduler.capacity.maximum-applications

      yarn.scheduler.capacity.<queue-path>.maximum-applications

      设置系统中可以同时运行和等待的应用数量。默认是10000。

    • yarn.scheduler.capacity.maximum-am-resource-percent
      yarn.scheduler.capacity.<queue-path>.maximum-am-resource-percent

      设置有多少资源可以用来运行app master,即控制当前激活状态的应用。默认是10%。

  • 队列管理

    • yarn.scheduler.capacity.<queue-path>.state

      队列的状态,可以使RUNNING或者STOPPED.如果队列是STOPPED状态,那么新应用不会提交到该队列或者子队列。同样,如果root被设置成STOPPED,那么整个集群都不能提交任务了。现有的应用可以等待完成,因此队列可以优雅的退出关闭。

    • yarn.scheduler.capacity.root.<queue-path>.acl_submit_applications

      访问控制列表ACL控制谁可以向该队列提交任务。如果一个用户可以向该队列提交,那么也可以提交任务到它的子队列。

    • yarn.scheduler.capacity.root.<queue-path>.acl_administer_queue

      设置队列的管理员的ACL控制,管理员可以控制队列的所有应用程序。同样,它也具有继承性。

      注意:ACL的设置是user1,user2 group1,group2这种格式。如果是*则代表任何人。空格表示任何人都不允许。默认是*.

  • 其他属性

    • yarn.scheduler.capacity.resource-calculator

      资源计算方法,默认是org.apache.hadoop.yarn.util.resource.DefaultResourseCalculator,它只会计算内存。DominantResourceCalculator则会计算内存和CPU。

    • yarn.scheduler.capacity.node-locality-delay

      调度器尝试进行调度的次数。一般都是跟集群的节点数量有关。默认40(一个机架上的节点数)
      一旦设置完这些队列属性,就可以在web ui上看到了。可以访问下面的连接:
      hostname:8088/scheduler

修改队列配置

如果想要修改队列或者调度器的配置,可以修改

1
vi $HADOOP_CONF_DIR/capacity-scheduler.xml

修改完成后,需要执行下面的命令:

1
$HADOOP_YARN_HOME/bin/yarn rmadmin -refreshQueues

注意:

  • 队列不能被删除,只能新增。
  • 更新队列的配置需要是有效的值
  • 同层级的队列容量限制想加需要等于100%。

五、公平调度器配置

yarn.resourcemanager.scheduler.class:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler

介绍

​ 公平调度器旨在为所有运行的应用公平分配资源。上面展示了同一个队列中的应用是如何实现资源公平享用的。然而公平共享实际也可以在多个队列间工作。

​ 想象两个用户A和B,分别拥有自己的队列(如下图)。A启动一个作业,在B没有需求时A会分配到全部可用资源;当A的作业仍在运行时B启动一个作业,一段时间后,按照我们先前看到的方式,每个作业都用了一半的集群资源。这时候,如果B启动第二个作业且其他作业仍在运行,那么第二个作业将和B的其他作业(这里是第一个)共享资源,因此B的每个作业将占用1/4的集群资源,而A仍继续占用一半的集群资源。最终的结果就是资源在用户之间实现了公平共享。

fair3app

队列配置

​ 通过一个名为fair-scheduler.xml的分配文件对公平调度器进行配置,该文件位于类路径下。(可以通过设置属性yarn.scheduler.fair.allocation.file来修改文件名)。当没有该分配文件时,公平调度器的工作策略同先前所描述的一样:每个应用放置在一个以用户名命名的队列中,队列是在用户提交第一个应用时动态创建的。

​ 假设在生产环境Yarn中,总共有四类用户需要使用集群,production、spark、default、streaming。为了使其提交的任务不受影响,我们在Yarn上规划配置了四个资源池,分别为production,spark,default,streaming。并根据实际业务情况,为每个资源池分配了相应的资源及优先级等,default用于开发测试目的.

ResourceManager上fair-scheduler.xml配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?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>

​ 队列的层次是通过嵌套<queue>元素实现的。所有的队列都是root队列的孩子,即使没有配到<root>元素里。

​ 队列有权重属性(这个权重就是对公平的定义),并把这个属性作为公平调度的依据。在这个例子中,当集群7.5,1,1,0.5资源给production,spark,streaming,default时便视作公平,这里的权重并不是百分比。注意,对于在没有配置文件时按用户自动创建的队列,它们仍有权重并且权重值为1。每个队列内部仍可以有不同的调度策略。队列的默认调度策略可以通过顶级元素<defaultQueueSchedulingPolicy>进行配置,如果没有配置,默认采用公平调度。尽管名称是“公平”,公平调度器也支持队列级别的FIFO策略,以及Dominant Resource Fairness(drf)策略。每个队列的调度策略可以被其内部的<schedulingPolicy>元素覆盖,在上面这个例子中,default队列就被指定采用fifo进行调度,所以,对于提交到default队列的任务就可以按照FIFO规则顺序的执行了。需要注意,spark,production,streaming,default之间的调度仍然是公平调度。每个队列可配置最大、最小资源占用数和最大可运行的应用的数量。

队列放置

​ 公平调度器采用了一套基于规则的系统来确定应用应该放到哪个队列。在上面的例子中,<queuePlacementPolicy> 元素定义了一个规则列表,其中的每个规则会被逐个尝试直到匹配成功。例如,上例第一个规则specified,则会把应用放到它指定的队列中,若这个应用没有指定队列名或队列名不存在,则说明不匹配这个规则,然后尝试下一个规则。primaryGroup规则会尝试把应用放在以用户所在的Unix组名命名的队列中,如果没有这个队列,会尝试下一个规则而不是创建队列。当前面所有规则不满足时,则触发default规则,把应用放在default队列中。

​ 当然,可以完全省略queuePlacementPolicy规则,此时队列放置默认遵从如下规则:

1
2
3
4
<queuePlacementPolicy>
<rule name="specified" />
<rule name="user" />
</queuePlacementPolicy>

​ 上面规则意思是,除非队列被准确的定义,否则会以用户名为队列名创建队列

​ 还有一个简单的配置策略可以使得所有的应用放入同一个队列(default),这样就可以让所有应用之间平等共享集群而不是在用户之间。这个配置的定义如下:

1
2
3
<queuePlacementPolicy>
<rule name="default" />
</queuePlacementPolicy>

​ 实现上面功能我们还可以不使用配置文件,直接设置yarn.scheduler.fair.user-as-default-queue=false,这样应用便会被放入default 队列,而不是各个用户名队列。另外,我们还可以设置yarn.scheduler.fair.allow-undeclared-pools=false,这样用户就无法创建队列了。

抢占

​ 在一个繁忙的集群中,当作业被提交到一个的空队列时,作业并不会马上执行,而是阻塞直到正在运行的作业释放系统资源。为了作业从提交到执行所需的时间更具预测性(可以设置等待的超时时间),公平调度器支持抢占(preemption)功能。抢占就是允许调度器杀掉占用超过其应占份额资源队列的容器,这些容器资源便可被分配到应该享有这些份额资源的队列中。需要注意抢占会降低集群的执行效率,因为被终止的容器需要被重新执行。

​ 通过设置一个全局的参数yarn.scheduler.fair.preemption=true可以全面启用抢占功能。此外,还有两个参数用来控制抢占的过期时间(这两个参数默认没有配置,需要至少配置一个来允许抢占容器):

1
2
minSharePreemptionTimeout  最小共享
fairSharePreemptionTimeout 公平共享

​ 如果队列在minimum share preemption timeout指定的时间内未获得被承诺的最小共享资源,调度器就会抢占其他容器。通过配置文件中的顶级元素<defaultMinSharePreemptionTimeout>为所有队列配置这个超时时间;我们还可以在<queue>元素内配置<minSharePreemptionTimeout>元素来为某个队列指定超时时间。

​ 类似,如果队列在fair share preemption timeout指定时间内未获得平等的资源的一半(这个比例可以配置),调度器则会进行抢占其他容器。这个超时时间可以通过顶级元素<defaultFairSharePreemptionTimeout>和元素级元素<fairSharePreemptionTimeout>分别配置所有队列和某个队列的超时时间。上面提到的比例可以通过<defaultFairSharePreemptionThreshold>(针对所有队列)和<fairSharePreemptionThreshold>(针对某个队列)进行配置修改超时阈值,默认是0.5。

Fair Scheduler与Capacity Scheduler区别

  • 资源公平共享:在每个队列中,Fair Scheduler可选择按照FIFO、Fair或DRF策略为应用程序分配资源。Fair策略即平均分配,默认情况下,每个队列采用该方式分配资源
  • 支持资源抢占:当某个队列中有剩余资源时,调度器会将这些资源共享给其他队列,而当该队列中有新的应用程序提交时,调度器要为它回收资源。为了尽可能降低不必要的计算浪费,调度器采用了先等待再强制回收的策略,即如果等待一段时间后尚有未归还的资源,则会进行资源抢占;从那些超额使用资源的队列中杀死一部分任务,进而释放资源
  • 负载均衡:Fair Scheduler提供了一个基于任务数的负载均衡机制,该机制尽可能将系统中的任务均匀分配到各个节点上。此外,用户也可以根据自己的需求设计负载均衡机制
  • 调度策略灵活配置:Fiar Scheduler允许管理员为每个队列单独设置调度策略(当前支持FIFO、Fair或DRF三种)
  • 提高小应用程序响应时间:由于采用了最大最小公平算法,小作业可以快速获取资源并运行完成

六、延迟调度delay scheduling

​ 如果申请一个正忙的节点,一般方式是放宽容器的本地限制,去到相同机架上的另一个节点来分配容器,但是实践来说,如果多等待一小会(不超过几秒),能够增加在所请求的忙节点上分配容器的机会,则可以提高集群的效率,这就叫延迟调度。容量调度器和公平调度器都支持延迟调度。

延迟调度的心跳机制(heartbeat)

​ 每个节点管理器周期性地(默认每秒1次)向资源管理器发送心跳请求,心跳中携带了节点管理器正在运行的容器/新容器可用的资源等信息,这对于每个申请节点的应用来说,每个心跳就是一个潜在的调度机会(scheduling opportunity)

调度机会:等待多少次心跳的问题

容量调度器:设置yarn.scheduler.capacity.node-locality-delay来配置延迟调度,设置为正整数,表示调度器在放松节点限制、改为匹配同一个机架上的其他节点之前,准备错过的调度机会数量

公平调度器:设置yarn.scheduler.fair.locality.threshold.node为0.5(集群规模的比例),表示调度器在接受同一机架上的不同节点之前,将一直等待集群中的一半节点都已经给过调度机会。还有个相关属性:yarn.scheduler.fair.locality.threshold.rack,表示接受另一个机架替代所申请的机架之前需要等待的时长阈值。

七、主导资源公平性(Dominant Resource Fairness,DRF)

​ 对于单一类型资源,如内存的调度,容量或公平性的概念很容易确定。但当有多种资源类型需要调度时,就会变得复杂。如一个用户的应用对CPU的需求打,但对内存的需求少;而另一个用户的需求相反,该如何比较?

​ YARN中调度器解决这个问题的思路是,观察每个用户的主导资源,并将其作为对集群资源使用的一个度量。这个方法成为主导资源公平性(Dominant Resource Fairness,DRF)

假设当前:

  • 集群资源:100vCPU,10TB内存
  • A请求资源:2vCPU,300GB内存,请求的资源在集群资源中占比分别为2%和3%,内存是A的主导资源
  • B请求资源:6vCPU,100GB内存,请求的资源在集群资源中占比分别为6%和1%,CPU是B的主导资源

由于B申请的资源是A的两倍(6% vs 3%),所以在公平调度下,B只分到A一般的容器数。

​ 默认情况下不用DRF,因此在资源计算期间,只需考虑内存,不必考虑CPU。对容量调度器进行配置后,可以使用DRF,将capacity-scheduler.xml中文件中的org.apache.hadoop.yarn.util.resource.DominantResourceCalculator设为yarn.scheduler.capacity.resource-calculator即可。

​ 公平调度器若要使用DRF,通过将分配文件中的顶层元素defaultQueueSchedulingPolicy设为drf即可。