Apache YARN(Yet Another Resource Negotiator的缩写)是Hadoop的集群资源管理系统。YARN运行在集群存储层(HDFS和HBase)上,一些分布式计算框架(如MapReduce和Spark等)作为YARN应用运行在集群计算层(YARN)和集群存储层上。
YARN通过两类长期运行的守护进程提供自己的核心服务:
1、管理集群上资源使用的资源管理器
2、运行在集群中所有节点上且能够启动和监控容器的节点管理器。
其中容器用于执行特定应用程序的进程。
下面简单按照图片描述一行YARN的运行过程:
1、客户端联系资源管理器,要求它运行一个 application master 进程;
2、资源管理器找到一个能够在容器中启动 application master 的节点管理器,application master 运行起来后能做什么依赖于应用本身,有可能是在所处容器中简单地运行一个运算,并将结果返回给客户端,那么进程就此结束;
3、或是向资源管理器请求更多地容器;
4、来运行一个分布式计算。
YARN有一个灵活的资源请求模型。当请求多个容器时,可以指定每个容器需要的计算机资源数量和,还可以指定对容器的本地限制要求。本地限制课用于申请位于指定结点或机架,或集群中任何位置的容器。若本地限制无法被满足,这种情况下要么不分配资源,或者可以选择放松限制。
通常情况下,当启动一个容器用于处理HDFS数据块时,应用将会向这样的节点申请容器:存储该数据块三个复本的节点,或是存储这些复本的机架中的一个节点。如果都申请失败,则申请集群中的任意节点。
YARN应用可以在运行中,既可以在最开始提出所有的请求,也可以为了满足不断变化的应用需要采取更为动态的方式在需要更多资源时提出请求。Spark 采用了前者,MapReduce 采用了后者。
YARN应用的生命期差异性很大,短则几秒,长则几月甚至几天。因此关注应用到用户运行的作业之间的映射关系对应用进行分类更有意义。
第一种模型:一个用户作业对应一个应用,这也是 MapReduce 采取的方式。
第二种模型:作业的每个工作流或每个用户对话对应一个应用。这种方法比第一种效率更高,因为容器可以在作业之间重用。Spark 采取这种模型。
第三种模型:多个用户共享一个长期运行的应用。这种应用通常作为一种协调者的角色运行。这种应用避免了启动新 application master 带来的开销,所以用户将活的非常低延迟的查询响应。Impala 使用了这种模型提供一个代理应用。
从无到有编写一个YARN应用相当复杂,但实际上有很多现成的应用在符合要求的情况下可以直接使用。
MapReduce 1 是指 Hadoop 的初始版本中的 MapReduce 分布式执行框架,用于区别于使用了YARN的MapReduce(在Hadoop及以后的版本中使用)。
1、可扩展性
YARN利用其资源管理器和 application master 分离的架构使得YARN能够在更大规模的集群上运行,,可以扩展到面向将近10000个结点和100000个任务。
2、可用性
当服务守护进程失败时,通过为另一个守护进程复制接管工作所需的状态以便其继续提供服务,从而可以获得高可用性。YARN中在资源管理器和 application master 之间进行了职责划分,高可用性随之程维龙一个分而治之的问题:先为资源管理器提供高可用性,再为YARN应用提供高可用性。
3、利用率
YARN中,一个节点管理器管理一个资源池,而不是指定的固定数目的 slot 。只要能获得运行任务的资源,应用就会正常进行。更进一步,YARN中的资源是精细化管理的,使得应用能够按需请求资源。
4、多租户
某种程度上,可以说YARN的最大优点在于向 MapReduce 以外的其他类型的分布式应用开放了Hadoop。MapReduce只是许多YARN应用中的一个。用户甚至可以在同一个YARN集群上运行不同版本的MapReduce。
调度就是分配资源的策略,在操作系统中有类似的概念。
FIFO调度器将应用放置在一个队列中,然后按照提交的顺序(先进先出)运行应用。
优点是简单易懂,不需要任何配置,但是不适合共享集群。
容量调度器有一个独立的专门队列保证小作业一提交就可以启动。因为这个队列容量是特意保留的,因此这种策略是以集群的利用率为代价的,也就是说,相同的大作业,容量调度器将比FIFO调度器花费更多的时间。
容量调度器允许多个组织共享一个Hadoop集群,每个组织可以分配到全部集群资源的一部分。每个渎职被配置一个专门的队列,每个队列被配置为可以使用一定的集群资源,队列内可进一步按层次划分。在一个队列内,可以使用FIFO对应用进行调度。
存在一种情况,队列中有多个作业并且队列资源不够用了,此时若仍有可用资源,那么容量调度器可能会将空余的资源分配给队列中的作业,即使会超出容量,这成为“弹性队列”。
正常情况下,容量调度器不会通过强行中止来抢占容器。因此,若一个队列开始时资源够用,但随着需求资源增长而导致资源开始不够用了,那么该队列只能等着其他队列释放容器资源。缓解这种情况的方法是:为队列设置一个最大容量限制,这样这个队列就不会过多侵占其他队列的容量了。但这是以牺牲队列弹性为代价的,因此需在不断尝试和失败中找到一个合理的折中。
容量调度器的基本配置文件的文件名为capacity-scheduler.xml
,下面以一个例子说明如何配置容量调度器的基本配置文件:
<configuration>
<property>
<name>yarn.schedular.capacity.root.queuesname>
<value>prod, devvalue>
property>
<property>
<name>yarn.schedular.capacity.root.dev.queuesname>
<value>eng, sciencevalue>
property>
<property>
<name>yarn.schedular.capacity.prod.capacityname>
<value>40value>
property>
<property>
<name>yarn.schedular.capacity.dev.capacityname>
<value>60value>
property>
<property>
<name>yarn.schedular.capacity.dev.maximum-capacityname>
<value>75value>
property>
<property>
<name>yarn.schedular.capacity.dev.eng.capacityname>
<value>50value>
property>
<property>
<name>yarn.schedular.capacity.dev.science.capacityname>
<value>50value>
property>
configuration>
其中属性maximum-capacity
用来进行最大容量限制,如果不设置这个量,那么对应的作业将有可能占用其所在队列的全部资源。
将应用放置在哪个队列中,取决于应用本身。如在 MapReduce 中,可通过设置属性mapreduce.job.queuename
来指定要用的队列。若队列不存在,则在提交时会报错;若不指定队列,则应用会被放在一个名为"default"
的默认队列中。
公平调度器不需要预留一定量的资源,因为调度器会在所有运行的作业之间动态平衡资源。第一个作业启动时将获得集群中的所有资源,当第二个作业启动时,它被分配到集群的一般资源,从而每个作业都能公平的共享资源。
需要注意的是,从七二个作业启动到获得公平共享资源之间会有事件滞后,这是因为它必须等待第一个作业使用的容器用完并释放出资源。
这种调度器既得到了较高的集群利用率,又能保证小作业及时完成。
公平调度器旨在为所有运行的应用公平分配资源。它既可以让同一个队列中的不同作业实现资源共享,也可以在多个队列间工作实现资源共享。
1、启用公平调度器
公平调度器的使用由属性yarn.resourcemanager.scheduler.class
的是设置决定的,默认使用容量调度器。需要改用公平调度器时,要将yarn-site.xml
中的yarn.resourcemanager.scheduler.class
设置为公平调度器的完全限定名:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fsir.FairScheduler
。
2、队列配置
使用名为fair-scheduler.xml的分配文件对公平调度器进行配置,使用与容量调度器相同的例子说明一下如何配置:
<allocations>
<defaultQueueSchedulingPolicy>fairdefaultQueueSchedulingPolicy>
<queue name="prod">
<weight>40weight>
<schedulingPolicy>fifoschedulingPolicy>
queue>
<queue name="prod">
<weight>60weight>
<queue name="eng" />
<queue name="science" />
queue>
<queuePlacementPolicy>
<rule name="specified" create="false" />
<rule name="primaryGroup" create="false" />
<rule name="default" create="dev.eng" />
queuePlacementPolicy>
allocations>
在本例子中,集群资源按40:60分配给prod和dev作为公平共享资源;eng和science未指定权重,因此会被平均分配。
每个队列可以设中不同的调度策略。队列的默认调度策略可以通过顶层元素defaultQueueSchedulingPolicy
设置,若省略,默认使用公平调度。公平调度器也支持队列级别的FIFO策略。
虽然例子中未设置,但每个队列仍可设置最大和最小资源数量。最小资源数量不是硬性限制,但调度器常用它对资源分配进行优先排序,若两个队列的资源都低于公平共享额度,那么远低于最小资源数量的哪个队列优先被分配资源。
3、队列放置
上面的配置文件中的queuePlacementPolicy
元素包含了一个规则列表,每条规则会被一次尝试直到匹配成功。specified
表示把应用放进指明的队列中;primaryGroup
会试着把应用放在以用户的主 Unix 组名命名的队列中;Default
在签署规则都不匹配时启用,把应用放进指定队列中。
还有两个比较常用的队列放置策略:
其一、
<queuePlacementPolicy>
<rule name="specified" />
<rule name="default" />
queuePlacementPolicy>
这是在省略queuePlacementPolicy
元素时默认的策略,即会以用户名为队列名创建队列。
其二、
<queuePlacementPolicy>
<rule name="default" />
queuePlacementPolicy>
这个策略是将所有应用放进同一个队列(default)中。
4、抢占
在一个繁忙的集群中,当作业被提交给一个空队列时,作业不会立刻启动,直到集群上已运行的作业释放了资源。为使作业从提交到执行所需时间可预测,公平调度器支持”抢占“功能。
抢占就是允许调度器终止那些占用资源超过了其公平共享份额的队列的容器,这些容器资源释放后可以分配给资源数量低于应得份额的队列。
将yarn.scheduler.fair.preemption
设置为true
,可以全面启用抢占功能。有两个相关的抢占超时设施设置:一个用于最小共享,一个用于公平共享。为了允许抢占容器,至少要设置其中一个。
YARN调度器都试图以本地请求为重。在一个繁忙的集群上,若一个应用请求某个节点,则很有可能此时有其他容器正在该节点上运行。显而易见的处理方法是,立刻放宽本地性需求,在同一机架中分配一个容器。但是,实践中发现,此时若等待一小段时间,可以增加在所请求容器上分配到一个容器的机会,从而提高集群效率,这就是延迟调度。
当使用延迟调度时,调度器不会简单的使用它收到的第一个调度机会,而是等待设定的最大数目的调度机会发生,然后才放松本地性限制并接收下一个调度机会。、
容量调度器用yarn.scheduler.capacity.node-locality-delay
配置延迟调度。设置为正整数,表示调度器在放松节点限制、改为匹配同一机架上的其他节点前,准备错过的调度机会的数量。公平调度器也使用调度机会的数量来决定延迟时间,不过时使用集群规模的比例来表示这个值(设置yarn.scheduler.fair.locality.threshold.node
)。
用户在运行应用时,有可能有多种资源类型需要调度(内存和CPU),特别是资源需求差距较大时,如何比较两个应用就变得复杂了。
YARN中调度器解决这个问题的思路是,观察每个用户的主导资源,并将其作为对集群资源使用的一个度量。这就是”主导资源公平性“(DRF)。
默认情况下不使用DRF,只考虑内存,不考虑CPU。
容量调度器使用DRF要将capacity-scheduler.xml
中的org.apache.hadoop.yarn.util.resource.DominantResourceCalculator
设为yarn.scheduler.capacity.resource-calculator
。公平调度器使用DRF,将分配文件中的defaultQueueSchedulingPolicy
设为drf
即可。
在单机/伪分布式的情况下,使用YARN的意义不大,只是换了一种方式来进行资源管理和调度,在单机上体现不出价值,甚至会变得更慢。而且,即使运行了YARN后,在运行程序等的过程中也不能直接观察出来。如果想要尝试一下,还是可以看这篇文章,有一个最简单的可以运行的配置。