分布式资源管理框架YARN

YARN概述

YARN(Yet Another Resource Negotiator,另一种资源协调者)是一种新的Hadoop资源管理器,它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来的巨大的好处。
YARN被引入Hadoop 2最初是为了改善MapReduce的实现,YARN是 MapReduce 的一个更加通用和高级的框架形式,并在其上增加了更多的功能。但它具有足够的通用性,同样可以支持其他的分布式计算模型。

YARN设计思路

YARN的设计是为了解决MapReduce1.0中的一些缺陷。

1.存在单点故障。
2.JobTracker“大包大揽”导致任务过重(任务多时内存开销大,上限4000节点)。
3.容易出现内存溢出(分配资源只考虑MapReduce任务数,不考虑CPU、内存)。
4.资源划分不合理(强制划分为slot ,包括Map slot和Reduce slot)。

YARN设计目标

设计通用的统一资源管理系统,同时运行长应用程序和短应用程序。
长应用程序
通常情况下,永不停止运行,
Service(Spark、Storm)、HTTP Server等。
短应用程序
短时间(秒级、分钟级、小时级)内会运行结束的程序,
MR job、Spark Job等。

YARN组件架构

Hadoop yarn详解 hadoop的yarn是什么_大数据


YARN组件架构图如上图所示,主要包括以下三大组件:

(1)ResourceManager(RM)

RM是Yarn的核心,是一个全局的资源管理器,负责整个系统的资源管理和分配,主要包括两个组件,即调度器(Scheduler)和应用程序管理器(Applications Manager)。

调度器接收来自ApplicationMaster的应用程序资源请求,把集群中的资源以“容器”的形式分配给提出申请的应用程序,容器的选择通常会考虑应用程序所要处理的数据的位置,进行就近选择,从而实现“计算向数据靠拢”。

容器(Container)作为动态资源分配单位,每个容器中都封装了一定数量的CPU、内存、磁盘等资源,从而限定每个应用程序可以使用的资源量。

调度器被设计成是一个可插拔的组件,YARN不仅自身提供了许多种直接可用的调度器,也允许用户根据自己的需求重新设计调度器。

应用程序管理器(Applications Manager)负责系统中所有应用程序的管理工作,主要包括应用程序提交、与调度器协商资源以启动ApplicationMaster、监控ApplicationMaster运行状态并在失败时重新启动等。

作用:
1.处理客户端请求
2.启动/监控ApplicationMaster
3.监控NodeManager
4.资源分配与调度

(2)ApplicationMaster(AM)
RM接收用户提交的作业,按照作业的上下文信息以及从NM收集来的容器状态信息,启动调度过程,为用户作业启动一个AM

AM的主要功能是:
1.当用户作业提交时,AMRM协商获取资源,RM会以容器的形式为AM分配资源;
2.把获得的资源进一步分配给内部的各个任务(Map任务或Reduce任务),实现资源的“二次分配”;
3.与NM保持交互通信进行应用程序的启动、运行、监控和停止,监控申请到的资源的使用情况,对所有任务的执行进度和状态进行监控,并在任务发生失败时执行失败恢复(即重新申请资源重启任务);
4.定时向RM发送“心跳”消息,报告资源的使用情况和应用的进度信息;
5.当作业完成时,AMRM注销容器,执行周期完成。

(3)NodeManager(NM)
NM是驻留在一个YARN集群中的每个节点上的代理,主要负责管理抽象的容器,只处理与容器相关的事情,而不具体负责每个任务(Map任务或Reduce任务)自身状态的管理,因为这些管理工作是由AM完成的,AM会通过不断与NM通信来掌握各个任务的执行状态。

主要负责以下内容:
1.容器生命周期管理。
2.监控每个容器的资源(CPU、内存等)使用情况。
3.跟踪节点健康状况。
4.以“心跳”的方式与RM保持通信。
5.向RM汇报作业的资源使用情况和每个容器的运行状态。
6.接收来自AM的启动/停止容器的各种请求 。

Yarn的工作流程

Hadoop yarn详解 hadoop的yarn是什么_大数据_02


YARN具体工作流程如图所示:

1.用户编写客户端应用程序,向YARN提交应用程序,提交的内容包括AM程序,启动AM的命令、用户程序等。

2.YARN中的RM负责接收和处理来自客户端的请求,为应用程序分配一个容器,在该容器中启动一个AM

3.AM被创建后会首先向RM注册。

4.AM采用轮询的方式向RM申请资源。

5.RM以“容器”的形式向提出申请的AM分配资源。

6.在加粗样式容器中启动任务(运行环境、脚本)。

7.各个任务向AM汇报自己的状态和进度。

8.应用程序运行完成后,AMRM的应用程序管理器注销并关闭自己。

YARN资源管理

资源调度资源隔离是YARN作为一个资源管理系统,最重要和最基础的两个功能。资源调度由RM完成,而资源隔离由各个NM实现。
  RM将某个NM上资源分配给任务(这就是所谓的“资源调度”)后,NM需按照要求为任务提供相应的资源,甚至保证这些资源应具有独占性,为任务运行提供基础的保证,这就是所谓的资源隔离。
  当谈及到资源时,我们通常指内存,CPU和IO三种资源。Hadoop YARN同时支持内存CPU两种资源的调度。
  内存资源的多少会会决定任务的生死,如果内存不够,任务可能会运行失败;相比之下,CPU资源则不同,它只会决定任务运行的快慢,不会对生死产生影响。
  YARN允许用户配置每个节点上可用的物理内存资源,注意,这里是“可用的”,因为一个节点上的内存会被若干个服务共享,比如一部分给YARN,一部分给HDFS,一部分给HBase等,
YARN配置的只是自己可以使用的,配置参数如下:
   (1) yarn.nodemanager.resource.memory-mb
表示该节点上YARN可使用的物理内存总重,默认是8192(MB),注意,如果你的节点内存资源不够8GB,则需要调减这个值,而YARN不会智能的探测节点的物理内存总里。
   (2) yarn.nodemanager.vmem-pmem-ratio
任务每使用1MB物理内存,最多可使用虚拟内存量,默认是2:1.
   (3) yarn.nodemanager.pmem-check-enabled
是否启动一个线程检查每个任务正使用的物理内存里,如果任务超出分配值,则直接将其杀掉,默认是true
   (4) yarn.nodemanager.vmem-check-enabled
是否启动一个线程检查每个任务正使用的虚拟内存里,如果任务超出分配值,则直接将其杀掉,默认是true
   (5) yarn.scheduler.minimum-allocation-mb
单个任务可申请的最少物理内存里,默认是1024(MB),如果一个任务申请的物理内存重少于该值,则该对应的值改这个数。
   (6) yarn.scheduler.maximum-allocation-mb
单个任务可申请的最多物理内存里,默认是8192(MB)。
   默认情况下,YARN采用了线程监控的方法判断任务是否超量使用内存,一旦发现超量,则直接将其杀死。由于Cgroups对内存的控制缺乏灵活性(即任务任何时刻不能超过内存上限,如果超过,则直接将其杀死或者报OOM),而Java进程在创建瞬间内存将翻倍,之后骤降到正常值,这种情况下,采用线程监控的方式更加灵活(当发现进程树内存瞬间翻倍超过设定值时,可认为是正常现象,不会将任务杀死),因此YARN未提供Cgroups内存隔离机制。
   目前的CPU被划分成虚拟CPU(CPU virtual Core),这里的虚拟CPU是YARN自己引入的概念,初衷是,考虑到不同节点的CPU性能可能不同,每个CPU具有的计算能力也是不一样的,比如某个物理CPU的计算能力可能是另外一个物理CPU的2倍,这时候,你可以通过为第一个物理CPU多配置几个虚拟CPU弥补这种差异。用户提交作业时,可以指定每个任务需要的虚拟CPU个数。在YARN中,CPU相关配置参数如下:
   (1) yarn.nodemanager.resource.cpu-vcores
表示该节点上YARN可使用的虚拟CPU个数, 默认是8.注意.目前推荐将该值设为与物理CPU核数数目相同,如果你的节点CPU核数不8个,则懦要调小这个值,而YARN不会智能的探测点物理CPU总数.
   (2) yarn.scheduler.minimum-allocation-vcores
单个任务可申请的最小虚拟cpu个数默认是1, 如果一个任务申请的CPU个数少于该数.则该对应的值改为这个数.
   (3) yarn.scheduler.maximum-allocation-vcores
单个任务可申请的最多虚拟CPU个数,默认是32。

YARN中的任务调度

理想情况下,YARN应用发出的资源请求应该给予满足。然而现实中资源是有点的,在一个繁忙的集群上,一个应用经常需要等待才能得到所需的资源。YARN调度器的工作就是根据既定策略为应用分配资源。调度通常是一个难题,而且没有一个所谓“最好”的策略,因此YARN提供了三种调度器供我们选择:FIFO调度器(FIFO Scheduler)容量调度器(Capacity Scheduler)和公平调度器(Fair Scheduler)

(1)FIFO调度器
FIFO调度器将应用放置在一个队列中,然后按照提交的顺序(先进先出)运行应用。首先为队列中第一个应用的请求分配资源,第一个应用的请求被满足后再依次为队列中下一个应用服务。
FIFO调度器的优点是简单易懂,不需要任何配置,但是不适合共享集群。大的应用会占用集群中的所有资源,所以每个应用必须等待直到轮到自己运行。在一个共享集群中,更适合使用容量调度器或者公平调度器。这两种调度器都允许长时间运行的作业能及时完成,同时也允许正在进行较小临时查询的用户能够在合理时间内得到返回结果。

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

单个作业使用的资源不会超过其队列容量。然而,如果队列中有多个作业,并且队列资源不够用的情况下,假如这时仍然有可用的空闲资源,那么容量调度器可能会将空余的资源分配给队列中的作业,哪怕这样会超出队列本来的容量。这称为“弹性队列”。

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

队列放置
将应用放置在哪个队列中,取决于应用本身。例如,在MapReduce中,可以通过设置属性mapreduce.job.queuename来指定要用的队列。如果队列不存在,则在提交时会发送错误。如果不指定队列,那么应用将被放在一个名为“default”的默认队列中。

(3)公平调度器配置
公平调度器旨在为所有运行的应用公平分配资源。我们想象有两个用户A和B,分别拥有自己的队列。当A首先启动一个作业,B没有需求的时候,A会分配到全部可用的资源;当A的作业仍在运行时B启动一个作业,A就会释放的一半的资源交给B。一段时间后,A和B每个作业都会用到一本的集群资源。这时如果B启动第二个作业且其他作业都在运行,那么第二个作业将和B的其他作业共享资源,这样B的每个作业就占用四分之一的集群资源,而A扔继续占用一半的集群资源。最终的结果就是资源在用户之间实现了公平共享。

1.启用公平调度器
公平调度器的使用由属性yarn.resourcemanager.scheduler.class的设置所决定。默认是使用容量调度器的。如果要是用公平调度器,需要将yarn.site.xml文件中的yarn.resourcemanager.scheduler.class设置为公平调度器的完全限定名:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler

2.队列配置
通过一个名为fair-scheduler.xml的分配文件对公平调度器进行配置。当没有该分配文件时,公平调度器的工作策略同先前所描述的一样:每个应用放置在一个以用户名命名的队列中,队列是在用户提交第一个应用时动态创建的。

通过分配文件可以为每个队列进行配置。这样可以对容量调度器支持的层次队列进行配置。队列的层次使用嵌套queue元素来定义。所有的队列都是root队列的孩子,即使实际上并没有嵌套近root queue元素里。队列中有权重元素,用于公平共享计算,权重并不是百分百,若没有指定权重,则会平均分配。

每个队列可以有不同的调度策略。队列的默认调度策略可以通过顶层元素defaultQueueSchedulingPolicy进行设置,如果省略,默认使用公平调度。尽管名称是“公平”,公平调度器也支持队列级别的FIFO策略,以及DRF策略。队列的调度策略也可以被该队列的schedulingPolicy元素指定的策略覆盖。其中每个队列也可以配置最大和最小资源数量,及最大可运行的应用的数量。最小资源数量不是一个硬性的限制,但是调度器常用它对资源分配进行优先排序。如果两个队列的资源都低于他们的公平共享额度,那么远低于最小资源数量的那个队列又分配资源。最小资源数量也会用于接下来将介绍的抢占行为。

3.队列放置
公平调度器使用一个基于规则的系统来确定应用应该放到哪个队列。`

<queuePlacementPolicy>
	<rule name = "specified" create = "false"/>
	<rule name = "primaryGroup" create = "false"/>
	<rule name = "default" queue = "dev.eng"/>
</queuePlacementPolicy>

如上述代码中,queuePlacementPolicy元素包含了一个规则明细表,每条规则都会被依次尝试知道匹配成功。第一条规则,specified表示吧应用放进所指明的队列中,如果没有指明,或者所指明的队列不存在,则规则不匹配,继续尝试下一条规则。primaryGroup规则会试着把应用放在以用户为主的Unix组名命名的队列中,如果没有这样的规则,则继续尝试下一条规则而不是创建队列。default规则则是一条兜底规则,当前面的规则都不满足时,将启用该条规则,把应用放进dev.eng队列中。
另一个简答的队列放置策略是,将所有的应用放进同一个队列(default)中。这样可以在应用之间公平共享资源,而不是在用户之间共享。

4.抢占
在一个繁忙的集群中,当作业被提交给一个空队列时,作业不会立刻启动,知道集群上已经运行的作业释放了资源。为了使作业从提交到执行所需的时间可预测,公平调度器支持“抢占”功能。

所谓抢占,就是允许调度器终止那些占用资源超过了其公平共享份额的队列的容器,这些容器资源释放后可以分配给资源数量低于应得份额的队列。注意,抢占会降低整个集群的效率,因为被终止的container(容器)需要重新执行。

通过将yarn.scheduler.fair.preemption设置为true,可以全面启用抢占功能。有两个相关的抢占超时设置:一个用于最小共享(minimum share preemption timeout),另一个用于公平共享(fair share preemption timeout),两者设定时间均为秒级。默认情况下,两个超时参数均不设置。所以为了允许抢占容器,需要至少设置其中一个超时参数。

如果队列在minimum share preemption timeout指定的时间内未获得被承诺的最小共享资源,调度器就会抢占其他容器。可以通过分配文件中的顶层元素defaultMinSharePreemptionTimeout为所有队列设置默认的超时时间,还可以通过设置每个队列的minSharePreemptionTimeout元素来为单个队列指定超时时间。

类似的,如果队列在fair share preemption timeout指定的时间内获得的资源仍然低于其公平共享份额的一半,那么调度器就会抢占其他容器。可以通过分配文件中的顶层元素defaultFairSharePreemptionTimeout为所有队列设置默认的超时时间,还可以通过设置每个队列的fairSharePreemptionTimeout元素为单个队列指定超时时间。通过设置defaultFairSharePreemptionThresholdtfairSharePreemptionThreshold(针对每个队列)可以修改超时阈值,默认值是0.5。

(4)延迟调度
所有的YARN调度器都试图以本地请求为重。在一个繁忙的集群上,如果一个应用请求某个节点,那么极有可能此时有其他容器正在该节点上运行。显而易见的处理是,立刻放宽本地性需求,在同一机架中分配一个容器。然而,通过实践发现,此时如果等待一小段时间(不超过几秒),能够戏剧性的增加在所请求的节点上分配到一个容器的机会,从而可以提高集群的效率。这个特性称之为延迟调度(delay scheduling)。容量调度器和公平调度器都支持延迟调度。

YARN中的每个节点管理器周期性的(默认每秒一次)向资源管理器发送心跳请求。心跳中携带了节点管理器中正运行的容器、新容器可用的资源等信息。这样对于一个计划运行一个容器的应用而言,每个心跳就是一个潜在的调度机会(scheduling spportunity)。

当使用延迟调度时,调度器不会简单的使用它收到的第一个调度机会,而是等待设定的最大数目的调度机会发生,然后才放松本地性限制并接收下一个调度机会。

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

公平调度器也使用调度机会的数量来决定延迟时间,尽管是使用集群规模的比例来表示这个值。例如将yarn.scheduler.fair.locality.threshold.node设置为0.5,表示调度器在接受同一机架中的其他节点之间,将一直等待直到集群中的一半节点都已经给过调取机会。还有个相关的属性yarn.scheduler.fair.locality.threshold.rack,表示在接受另一个机架替代所申请的机架之前需要等待的时长阈值。

YARN通信协议

RPC协议是连接各个组件的“大动脉”,了解不同组件之间的RPC协议有助于我们更深人地学习YARN框架。在YARN中,任何两个需相互通信的组件之间仅有一个RPC协议,面对于任何一个RPC协议,通信双方有一端是Client, 另一端为Server, 且Client总是主动连接 Server的,因此,YARN实际上采用的是拉式(ull-based) 通信模型
YARN主要由以下几个RPC协议组成:
  (1)JobClient(作业提交客户端)与RM之间的协议—ApplicationClientProtocol:JobClient通过该RPC协议提交应用程序、查询应用程序状态等。
  (2)Admin(管理员)与RM之间的通信协议----ResourceManagerAdministrationProtocol::Admin通过该RPC协议更新系统配置文件,比如节点黑白名单、用户队列权限等。
  (3)AM与RM之间的协议一ApplicationMasterProtocol: AM通过该RPC协议向RM注册和撒销自己,并为各个任务申请资源。
  (4)AM与NM之间的协议一ContainerManagementProtocol: AM通过该RPC要求NM启动或者停止Container,获取各个Container的使用状态等信息。
  (5)NM与RM之间的协议一ResuceTracker: NM通过该RPC协议向RM注册,并定时发送心跳信息汇报当前节点的资源使用情况和Container运行情况。