YARN任务资源调度

YARN是Hadoop2中引入的集群资源管理系统,本文详细解析YARN的运行机制、资源请求模型、应用生命期以及如何构建YARN应用。对比MapReduce1,YARN在可扩展性、可用性和利用率上有所提升,支持多租户。文章还深入介绍了YARN的调度器,包括FIFO、容量和公平调度器的配置与使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

apache是Hadoop的集群资源管理系统,YARN被引入Hadoop2,最初是为了改善MapReduce的实现,但它具有足够的通用性,同时可以支持其他的分布式计算模式。

剖析YARN应用运行机制

YARN通过两类长期运行的守护进程提供自己的核心服务:管理集群上资源使用的资源管理器(ResourceManager)和运行在集群中所有集群上且能够启动和监控容器的节点管理器(nodeManager)。容器是用来执行特定应用程序的进程,每个容器都有资源限制(内存、CPU等)。

为了在YARN上运行一个应用,首先,客户端连接资源管理器,要求它运行一个application master进程。然后,资源管理器找到一个能够在容器中启动application master的节点管理器。准确的说,application master一旦运行起来后能够做些什么依赖于应用本身。有可能是在所处的容器简单的运行一个计算,并且将计算结果返回到客户端;或者是向资源管理器请求更多的容器以便于运行一个分布式计算,后者是MapReduceYARN的应用所做的事情。

PS:YARN本身不会为应用的各部分(客户端、master和进程)彼此间通信提供任何手段。大多数重要的YARN应用使用某种形式的远程通信机制(例如Hadoop的RPC层)来向客户端传递状态更新和返回结果,单数这些通信机制都是专属于各应用的。

资源请求

    YARN有一个灵活的资源请求模型。当请求多个容器时,可以指定每个容器需要的计算机资源数量(内存和CPU),还可以指定对容器的本地限制要求。

    本地化对于确保分布式数据处理算法高效使用集群带宽非常重要,因此,YARN允许一个应用为所申请的容器指定本地限制。本地限制可用于申请位于指定接点或机架,或集群中任何位置(机架外)的容器。

    当启动一个容器用于处理HDFS数据块(为了在MapReduce中运行一个map任务)时,用户将会像这样的节点申请容器:存储该数据的三个复本的节点,或是存储这些复本的机架中的一个节点。如果都申请失败,将会申请集群中的任意节点。

应用生命期(取决于每个容器运行的时间)

    YARN应用的生命期差异性很大:有几秒的短期应用,也有连续运行几天甚至几个月的长期应用。与其关注应用运行多长时间,不如按照应用到用户运行的作业之间的映射关系对应用分类更有意义。最简单的模型是一个用户作业对应一个应用,这也是MapReduce采取的方式。

    第二种模型是,作业的每个工作流或每个用户对话(可能并无关联性)对应一个应用。这种方法要比第一种效率更高,因为容器可以在作业之间重用,并且有可能缓冲作业之间的中间数据。Spark采用的是这种模型。

    第三种模型是,多个用户共享一个长期运行的应用。这种应用通常是作为一种协调者的角色运行。例如:Apache Slider有一个长期运行的application master,主要用于启动集群上的其他应用。这种应用的好处是,避免了启动新的application master带来的开销,一个总是开启的application master意味着用户将获得非常低延迟的查询响应。

构建YARN应用

YARN与Map Reduce1相比

    有时用"Map Reduce1"来指代Hadoop初代版本中的Map Reduce分布式执行框架,以区别于使用了YARN(Hadoop2以及以后的版本)的Map Reduce2。

    Map Reduce1中,有两类守护进程控制着作业执行过程:一个jobtracker及多个tasktracker。jobtracker通过调度task tracker上运行的任务来协调所有运行在系统上的作业。tasktracker在运行任务的同时将运行进度报告给jobtracker,jobtracker由此记录每项作业任务的整体进度情况。如果其中一个任务失败,jobtracker可以在另一个tasktracker节点上重新调度该任务。

  Map Reduce1中,jobtracker同时负责作业调度(将任务与task tracker匹配)和进度监控(跟踪任务、重启失败或迟缓的任务;记录任务流水,如维护计数器的计数)。相比之下,YARN中,这些职责是由不同的实体担负的:它们分别是资源管理器和application master(每个Map Reduce作业一个)。jobtracker也负责存储已完成作业的作业历史,但是也可以运行一个作业历史服务器作为一个独立的守护进程来取代jobtracker。在YARN中,与之等价的角色是时间轴服务器(timelineServer),他主要是用于存储应用历史。

    在YARN中,与Map Reduce1中相对应的映射关系如下:

jobtracker----------------------------资源管理器、application master、时间轴服务器

Task tracker-------------------------节点管理器

slot-------------------------------------容器

YARN的很多设计是为了解决Map Reduce1的局限性。使用YARN的好处包括以下几个方面。

可扩展性(Scalability)

可用性(Availability)

当服务守护进程失败时,通过为另一个守护进程复制接管工作所需的状态以便其继续提供服务,从而获得高可用性。然而。jobtracker内存中大量快速变化的复杂状态(例如,每个任务状态每几秒会更新一次)使得改进jobtracker服务获得高可用性非常困难。

由于YARN中jobtracker在资源管理器和application master 之间进行了职责划分(分为了资源管理器、application master、时间轴服务器),高可用的服务随之成为一个分而治之问题:先为资源管理器提供高可用,   再为YARN应用(针对每个人应用)提供高可用。实际上,对于资源管理器和application master,Hadoop2都支持MapReduce作业的高可用性。

利用率(Utilization)

MapReduce1中,每个tasktracker都配置有若干长度的slot,这些slot是静态分配的,在配置的时候就被划分成为map slot和reduce slot。一个map slot和一个reduce slot仅能够用于运行一个map和reduce任务。

YARN中,一个节点管理器管理一个资源池,而不是固定数量的slot,YARN上运行的MapReduce不会出现由于集群中仅有map slot可用导致reduce任务必须等待的情况,而MapReduce1会有这样的问题。如果能够获得运行任务的资源,name应用就会正常进行

更近一步,YARN中的资源是精细化管理的,这些一个应用能够按需请求资源,而不是请求一个不可分割的、对于特定的任务而言可能会太大(浪费资源)或太小(可能会导致失败)的slot。

多租户(Multitenancy)

在某种程度上,可以说YARN的最大优点在于向MapReduce以外的其他类型的分布式应用开放了Hadoop。MapReduce仅仅是许多YARN应用中的一个。

用户甚至可以在同一个YARN集群上运行不同版本的MapReduce,这使得升级MapReduce的过程更好管理。(注意,MapReduce的一些部件,例如作业历史服务器和shuffle句柄,和YARN自身一样,仍需要在集群范围内升级。)

YARN中的调度

    理想情况下,YARN应用发出的资源请求应该立即给予满足。然而现实中的资源是有限的,在一个繁忙的集群中,一个应用经常需要等待才能得到所需要的资源。YARN调度器的工作就是根据既定策略为应用分配资源,调度通常是一个难题,并没有一个所谓“最好”的策略,所以YARN提供了多种调度器和可配置策略。

    调度选项

        YARN中有三种调度器可用:FIFO调度器、容量调度器和公平调度器。

FIFO调度器

FIFO调度器将应用放置在一个队列中,然后按照提交的顺序(先进先出)运行应用。首先为队列中第一个应用的请求分配资源,第一个应用的请求被满足后再依次为队列中下一个应用服务。

FIFO调度器的优点是:简单易懂,不需要任何配置,但是不适合共享集群。大的应用会占用集群中的所有资源,所以每个应用必须等待直到轮到自己运行。

FIFO调度器的缺点是:后面的任务必须等待前面的任务执行完毕以后才能够执行。

容量调度器

在一个共享集群中,更适合使用容量调度器或者公平调度器。这两种容器都允许长时间运行的作业能及时完成,同时也允许正在进行较小临时查询的用户能后在合理的时间内得到返回结果。

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

使用容量调度器的缺点是:大作业的执行时间会变长,因为将资源分配给小作业执行。

优点:小作业一经提交就能够执行,不需要等待分配资源。

公平调度器

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

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

总结:

    如果业务逻辑比较简单或者是刚刚接触Hadoop,建议使用FIFO队列;如果想要控制部分应用的优先级同时又想要充分利用集群资源,建议使用容器调度器;如果想要多用户或者多队列公平的共享集群中的所有资源,建议使用公平调度器。

    容量调度器配置

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

    如同上图所示,单个作业使用的资源会不会超过其队列的容量。应该是存在这种情况的,然而,如果队列中有多个作业,并且在队列中资源不够使用了呢?这时如果仍有可用的空闲资源,那么容器调度器可能会将空余的资源分配给队列中的作业,哪怕会超出队列容量。这称为“弹性队列”。

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

假设一个队列的结构层次是:

root

|_____prod

|_____dev

             |____eng

             |____science

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

队列放置

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

PS:对于容量调度器,队列名应该是队列层次的最后一部分,完整的队列层次名是不会被识别的。例如,对于上述的配置范例,prod和eng是合法的队列名,但是root.dev.eng和dev.eng作为队列名是无效的

公平调度器配置

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

1、启动公平调度器(集群默认使用的是容量调度器)

    公平调度器的使用是由属性yarn.resourcemanager.scheduler.class的设置所决定。默认使用的是容量调度器(在一些Hadoop分布式项目,如CDH中默认使用的是公平调度器),如果想要使用公平调度器,需要将yarn-site.xml文件中的yarn.resourcemanager.scheduler.class设置为公平调度器的完全限定名:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler。

2、队列配置

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

    通过分配文件可以为每个队列进行配置,这样可以对容量调度器支持的层次队列进行配置。例如可以像为容量调度器所做的那样,使用分配文件定义prod和dev。

<?xml version="1.0"?>
<allocations>
<defaultQueueSchedulingPolicy>fair</defaultQueueSchedulingPolicy>

<queue name="prod">
    <weight>40</weight>
    <schedulingPolicy>fifo</schedulingPolicy>
</queue>

<queue name="dev">
    <weight>60</weight>
    <queue name="eng" />
    <queuq name"science" />
</queue>

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

队列层次使用嵌套queue元素来定义。所有的队列都是root队列的孩子,即使实际上并没有嵌套进root queue元素里。这里把dev队列又划分成eng和science两个队列。

    队列中有权重元素,用于公平共享计算。在这个例子中,当集群资源按照40:60的比例分配给prod和dev时,集群分配认为是公平的。eng和science队列没有指定权重,因此它们会被平均分配。权重并不是100%,例子中是为了简单起见使用了相加之和为100的数,也可以为prod和dev队列分别指定2和3的权重,在效果上是一样的(按照比例分配,40%:60%和2:3是一个概念)。

PS:当设置权重时,记住要考虑默认队列和动态创建的队列(假如以用户名创建的队列)。虽然在分配文件中没有为它们指定权重,但是它们仍有值为1的权重。防止这类队列分配不到任何的集群资源。

    每个队列可以有不同的策略。队列的默认调度策略可以通过顶层元素defaultQueueSchedulingPolicy进行设置,如果省略。默认使用公平调度。尽管名称是公平,公平调度器也支持队列级别的FIFO策略,以及Dominant Resource Fairness(drf)策略。

    队列的调度策略可以被该队列的schedulingPolicy元素指定的策略覆盖。在上述例子中,由于我们希望每个生产性作业能够顺序运行且在最短可能的时间内结束,所以prod队列使用FIFO调度策略。值得注意的是,在prod和dev队列之间,eng和science队列之间及内部划分资源仍然使用了公平调度。

    尽管上述的分配文件中没有展示,每个队列仍可配置最大和最小的资源数量,以及最大可运行的应用的数量。最小的资源数量不是一个硬性的限制,但是调度器常用它对资源分配进行优先排序。如果两个队列的资源都低于他们的公平共享额度,那么远低于最小资源数量的那个队列先被分配资源。最小资源数量也会用于抢占行为。

3、队列放置

    公平调度器使用一个基于规则的系统来确定应用应该放到哪个队列。在之前的分配文件中,queuePlacementPolicy元素包含了一个规则列表,每条规则会被依次尝试直到匹配成功。第一条规则,specified,表示把应用放进所指明的队列中,如果没有指明,或如果所指明的队列不存在,则规则不匹配,继续尝试下一条规则。primaryGroup规则会试着把应用放在以用户的主Unix组名命名的队列,如果没有这样的队列,则继续尝试下一条规则而不是创建一个队列。default规则是一条兜底规则,当前面的规则都不匹配时,将会启用该条规则,将应用放置在dev.eng队列中。

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

<queuePlacementPolicy>
    <rule name="specified" />
    <rule name="user" />
</queuePlacementPolicy>

换而言之,除非明确定义队列,否则必要时会以用户名为队列名创建队列。

   另一个简单的队列放置策略是,将所有的应用放进同一个队列(default)中。这样可以在应用之间公平共享资源,而不是在用户之间共享策略定义等价于以下规则:

<queuePlacementPolicy>
    <rule name="dafault" />
</queuePlacementPolicy>

PS:不使用分配文件也可以设置以上策略,通过将属性yarn.scheduler.fair.user-as-dafault-queue设置为false,应用就会被放入到default队列,而不是各个用户的队列。另外,将属性yarn.scheduler.fair.allow-undeclared-pools设置为false,用户便不能随便创建队列了。

4、抢占

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

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

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

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

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

延迟调度

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

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

    在使用延迟调度之后,调度器(容量调度器或公平调度器)不会简单的使用它收到的调度机会,而是等待设定的最大数目的调度机会发生,然后放松本地行限制并且接收下一次的调度机会。

    对于容量调度器而言,可以通过设置yarn.scheduler.capacity.node-locality-delay来配置延迟调度。设置为正整数,表示调度器正在放松节点限制、改为匹配同一机架上的其他节点,准备错过的调度机会的数量。(设置为正数之后,放松节点限制是指的是,可以不再本地节点上运行,但是匹配同一机架上的节点,正数的值为整备错过的调度机会的数量)

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

主导资源公平性

    打个比喻,如果集群一共有100个CPU和10TB的资源。应用A请求的容器资源为2个CPU和300GB内存,应用B请求的容器资源为6个CPU和100GB内存。A请求的资源在集群资源中所占的比例为2%和3%,由于内存占比(3%)大于CPU占比(2%)所以内存是A的主导资源。B请求的资源在集群资源中占比分别为6%和1%,所以CPU是B的主导资源。但是由于B申请的资源是A的两倍(6%vs3%),所以在公平调度下,B将分配到集群一半的资源。(这里的申请的资源是指的是主导资源)。

    但是在默认情况下不适用主导资源公平性,因此在资源计算期间,只考虑内存,不必考虑CPU。

    在容量调度器配置之后,可以使用DRF(主导资源公平性),将capacity-scheduler.xml文件中的org.apache.hadoop.yarn.util.resource.DominantResourceCalculator设为yarn.scheduler.capacity.resource-calculator即可。

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

参考文献:Hadoop权威指南第4章YARN

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值