Hadoop—关于YARN

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/maydaysar/article/details/82747073

Apache YARN(Yet Another Resource Negotiator)是Hadoop的集群资源管理系统。YARN被引入Hadoop 2,最初是为了改善MapReduce的实现,但它具有足够的通用性,同样可以支持其他的分布式计算模式。
  YARN提供请求和使用集群资源的API,但这些API很少直接用于用户代码。相反,用户代码中用的是分布式计算框架提供的更高层的API,这些API建立在YARN之上且向用户隐藏了资源管理细节。
  这里写图片描述
  一些分布式计算框架(MapReduce、Spark等)作为YARN应用运行在集群计算层(YARN)和集群存储层(HDFS和HBase)上。
  还有一层应用是建立在图4-1所示的框架之上。如pig,hive和Crunch都是运行在MapReduce,Spark或Tez(或三个都可)之上的处理框架,它们不和YARN直接打交道。

剖析YARN应用运行机制

YARN通过两类长期运行的守护进程(Daemon)提供自己的核心服务:管理集群上资源使用的资源管理器(resource manager)、运行在集群中所有节点上且能够启动和监控容器(container)的节点管理器(node manager)。容器用于执行特定应用程序的进程,每个容器都有资源限制(内存、CPU等)。一个容器可以是一个Unix进程,也可以是一个Linux cgroup,这取决于YARN的配置。
  YARN运行
  上图表示了YARN是如何运行一个应用的。为了在YARN上运行一个应用,首先,客户端联系资源管理器,要求它运行一个application master进程(步骤1)。然后资源管理器找到一个能够在容器中启动application master的节点管理器(步骤2a和2b)。准确的说,application mast一旦运行起来后能做些什么依赖于应用本身。有可能是在所处的容器中简单地运行一个计算,并将结果返回给客户端;或是想资源管理器请求更多的容器(步骤3),以用于运行一个分布式计算(步骤4a和4b)。后者是MapReduce YARN应用所做的事情。
  注意,YARN本身不会为应用的各部分(客户端、master和进程)彼此间通信提供任何手段。大多数重要的YARN应用使用某种形式的远程通信机制(例如Hadoop的RPC层)来向客户端传递状态更新和返回结果,但是这些通信机制都是专属于各应用的。

资源请求

YARN有一个灵活的资源请求模型。当请求多个容器时,可以指定每个容器需要的计算资源数量(内存和CPU),还可以指定对容器的本地限制要求。
  本地化对于确保分布式数据处理算法高效实用集群带宽非常重要,因此,YARN允许一个应用为所申请的容器指定本地限制。本地限制可用于申请位于指定节点或机架,或集群中任何位置(机架外)的容器。
  有时本地限制无法被满足,这种情况下要么不分配资源,或者可选择放松限制。例如,一个节点由于已经运行了别的容器而无法再启动新的容器,这时如果有应用请求该节点,则YARN将尝试在同一机架中的其他节点上启动一个容器,如果还不行,则会尝试集群中的任何一个节点。
  通常情况下,当启动一个容器用于处理HDFS数据块(为了在MapReduce中运行一个map任务)时,应用将会向这样的节点申请容器:存储该数据块三个复本的节点,或是存储这些复本的机架中的一个节点。如果都申请失败,则申请集群中的任意节点。
  YARN应用可以在运行中的任意时刻提出资源申请。例如,可以在最开始提出所有的请求,或者为了满足不断变化的应用需求,采取更为动态的方式在需要更多资源时提出请求。
  Spark采用了上述第一种方式,在集群上启动固定数量的执行器。另一方面,MapReduce则分两步走,在最开始时申请map任务容器,reduce任务容器的启用则放在后期。同样,如果任何任务出现失败,将会另外申请容器以重新运行失败的任务。

应用生命期

YARN应用的生命期差异性很大:有几秒的短期应用,也有连续运行几天甚至几个月的长期应用。与其关注应用运行多长时间,不如按照应用到用户作业的作业之间的映射关系对应用进行分类更有意义。最简单是模型是一个用户作业对应一个应用,这也是MapReduce采取的方式。
  第二种模型是,作业的每个工作流或每个用户对话(可能并无关联性)对应一个应用。这种方法要比第一种情况效率更高,因为容器可以在作业之间重用,并且有可能缓存作业之间的中间数据。Spark采取的是这种模型。
  第三种模型是,多个用户共享一个长期运行的应用。这种应用通常是作为一种协调者的角色在运行。例如,Apache Slider有一个长期运行的application master,主要用于启动集群上的其他应用。Impala也使用这种模型提供了一个代理应用,Impala守护进程通过该代理请求集群资源。由于避免了启动新application master带来的开销,一个总是开启的application master意味着用户将获得非常低延迟的查询响应。

YARN与MapReduce 1相比

有时用“MapReduce 1”来指代Hadoop初识版本(版本1及更早期版本)中的MapReduce分布式执行框架,以区别于使用YARN(Hadoop 2及以后的版本)的MapReduce 2。
  MapReduce 1中,有两类守护进程控制着作业执行过程:一个jobtracker及一个或多个tasktracker。jobtracker通过调度tasktracker上运行的任务来协调所有运行在系统上的作业。tasktracker在运行任务的同时将运行进度报告发送给jobtracker,jobtracker由此记录每项作业任务的整体进度情况。如果其中一个任务失败,jobtracker可以在另一个tasktracker节点上重新调度该任务。
  MapReduce 1中,jobtracker同时负责作业调度(将该任务与tasktracker匹配)和任务进度监控(跟踪任务、重启失败或迟缓的任务;记录任务流水,如维护计数器的计数)。相比之下,YARN中,这些职责是由不同的实体担负的:它们分别是资源管理器和application master(每个MapReduce作业一个)。jobtracker也负责存储已完成作业的作业历史,但是也可以运行一个作业历史服务器作为一个独立的守护进程来取代jobtracker。在YARN中,与之等价的角色是时间轴服务器,它主要用于存储应用历史。
  YARN中与tasktracker等价的角色是节点管理器。下图为MapReduce 1和YARN中的映射关系。
  这里写图片描述
  YARN的很多设计是为了解决MapReduce 1的局限性,使用YARN的好处包括以下几个方面:

  • 列扩展性(Scalability)
      与MapReduce 1相比,YARN可以在更大规模的集群上运行。当节点数达到4000,任务数达到40000时,MapReduce 1会遇到可扩展性瓶颈,瓶颈源自于jobtracker必须同时管理作业和任务这样一个事实。YARN利用其资源管理器和application master分离的架构优点克服了这个局限性,可以扩展到面向将近10000个结点和100000个任务。
      与jobtracker相比,一个应用的每个实例(这里指一个MapReduce作业)都对应一个专门的application master,该管理进程在(master)在应用的持续期间运行。这个模型实际上与初始的Google MapReduce论文中所描述的更接近。论文中描述了如何启动一个管理(master)进程以协调运行在一系列工作(worker)上的map和reduce任务。
  • 可用性(Availability)
      当服务守护进程失败时,通过为另一个守护进程复制接管工作所需的状态以便其继续提供服务,从而可以获得高可用性(HA,High availability)。然而,jobtracker内存中大量快速变化的复杂状态(例如,每个任务状态每几秒会更新一次)使得改进jobtracker服务获得高可用性非常困难。
      由于YARN中jobtracker在资源管理器和application master之间进行了职责划分,高可用的服务随之成为一个分而治之的问题:先为资源管理器提供高可用性,再为YARN应用(针对每个应用)提供高可用性。实际上,对于资源管理器和application master,Hadoop 2都支持MapReduce作业的高可用性。
  • 利用率
      MapReduce 1中,每个tasktracker都配置有若干固定长度的slot,这些slot是静态分配的,在配置的时候就被划分为map slot和reduce slot。一个map slot仅能用于运行一个map任务;一个reduce slot仅能用于运行一个reduce任务。
      YARN中,一个节点管理器管理一个资源池,而不是指定的固定数目的slot。YARN上运行的MapReduce不会出现由于集群中仅有map slot可用导致reduce任务必须等待的情况,而MapReduce 1则会有这样的问题,如果能够获得运行任务的资源,那么应用就会正常运行。
      更进一步,YARN中的资源是精细化管理的,这样一个应用能够按需请求资源,而不是请求一个不可分割的、对于特定的任务而言可能会太大(浪费资源)或太小(可能会导致失败)的slot。
  • 多租户
      在某种程度上,可以说YARN的最大优点在于向MapReduce以外的其他类型的分布式应用开放了Hadoop。MapReduce仅仅是许多YARN应用中的一个。
      用户甚至可以在同一个YARN集群上运行不同版本的MapReduce,这使得升级MapReduce的过程更好管理。(注意,MapReduce的一些部件,例如作业历史服务和shuffle句柄,和YARN自身一样,仍然需要在集群范围内升级。)

YARN中的调度

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

调度选项

YARN中有三种调度器可用:FIFO调度器(FIFO Scheduler),容量调度器(Capacity Scheduler)和公平调度器(Fair Scheduler)。FIFO调度器将应用放置在一个队列中,然后按照提交的顺序(先进先出)运行应用。首先为队列中第一个应用的请求分配资源,第一个应用的请求被满足后再依次为队列中下一个应用服务。
  FIFO调度器的优点:简单易懂,不需要任何配置,但是不合适共享集群。大的应用会占用集群中的所有资源,所有每个应用必须等待直到轮到自己运行。在一个共享集群中,更适合使用容量调度器或公平调度器。这两种调度器都允许长时间运行的作业能及时完成,同时也允许正在进行较小临时查询的用户能够在合理时间内得到返回结果。
  使用容量调度器是,一个独立的专门队列保证小作业一提交就可以启动,由于队列容量是为那个队列中的作业所保留的,因此这种策略是以整个集群的利用率为代价的。这意味着与使用FIFO调度器相比,大作业执行的时间要长。
  使用公平调度器时,不需要预留一定量的资源,因为调度器会在所有运行的作业之间动态平衡资源。这个大作业启动时,它也是唯一运行的作业,因而获得集群中所有的资源。当第二个小作业启动时,它被分配到集群的一半资源,这样每个作业都能公平共享资源。
  注意,从第二个作业的启动到获得公平共享资源之间会有时间滞后,因为它必须等待第一个作业使用的容器用完并释放资源。当小作业结束且不再申请资源后,大作业将回去再次使用全部的集群资源。最终的效果是:既得到了较高的集群利用率,又能保证小作业能及时完成。

容量调度器配置

容量调度器允许多个组织共享一个Hadoop集群,每个组织可以分配到全部集群资源的一部分。每个组织被配置一个专门的的队列,每个队列被配置为可以使用一定的集群资源。队列可以进一步按层次划分,这样每个组织内的不同用户能够共享该组织队列所分配的资源。在一个队列内,使用FIFO调度器策略对应用进行调度。
  单个作业使用的资源不会超过其队列容量。然而,如果队列中有多个作业,并且队列资源不够用了呢?这时如果仍有可用的空闲资源,那么容量调度器会将空余的资源分配给队列中的作业,哪怕这会超出队列容量。这称为“弹性队列”。
  正常操作时,容器调度器不会通过强行中止来抢占容器(container)。因此,如果一个队列一开始资源够用,然后随着需求增长,资源开始不够用时,那么这个队列就只能等着其他队列释放容器资源。缓解这种情况的方法是,为队列设置一个最大容量限制,这样这个队列就不会过多侵占其他队列的容量了。当然,这样做是以牺牲队列弹性为代价的,因此需要在不断尝试和失败中找到一个合理的折中。

队列放置

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

公平调度器配置

公平调度器旨在为所有运行的应用公平分配资源。想象两个用户A和B,分别拥有自己的队列,A启动一个作业,在B没有需求时分配到全部可用资源;当A的作业仍在运行时B启动一个作业,一段时间后,按照我们先看到的方式,每个作业都用到一半的集群资源。这时,如果B启动第二个作业且其他作业仍在运行,那么第二个作业将和B的其他作业共享资源,因此B的每个作业将占用四分之一的集群资源,而A仍然继续占用一半的集群资源,最终的结果就是资源在用户之间实现了公平共享。
  1、启动公平调度器
  公平调度器的使用由属性yarn.resourcemanager.scheduler.class的设置所决定。默认是使用容量调度器(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来修改文件名)。当没有该分配文件时,公平调度器的工作策略同先前所描述一样:每个应用放置在一个以用户名命名的队列中,队列是在用户提交第一个应用时动态创建的。
  通过分配文件可以为每个队列进行配置。这样可以对容量调度器支持的层次队列进行配置。
  每个队列可以有不同的调度策略。队列的默认调度策略可以通过顶层元素defaultQueueSchedulingPolicy进行设置,如果省略,默认使用公平调度。尽管名称是“公平”,公平调度器也支持队列级别的FIFO策略,以及Dominant Resource Fairness(drf)策略。
  队列的调度策略可以被该队列的schedulingPolicy元素指定的策略覆盖。
  3、队列配置
  公平调度器使用一个基于规则的系统来确定应用应该放在哪个队列。
  4、抢占
  在一个繁忙的集群中,当作业被提交给一个空队列时,作业不会立刻启动,直到集群上已经运行的作业释放了资源。为了使作业从提交到执行所需的时间可预测,公平调度器支持“抢占”功能。
  所谓抢占,就是允许调度器终止那些占用资源超过了其公平共享份额的队列的容器,这些容器资源释放后可以分配给资源数量低于应得份额的队列。注意,抢占会降低整个集群的效率,因为被终止的container需要重新执行。
  通过将yarn.scheduler.fair.preemption设置为true,可以全面启用抢占功能。有两个相关的抢占超时设置,一个用于最小共享(minimum share preemption timeout),另一个用于公平共享(fair share preemption timeout),两者设定时间均为秒级。默认情况下,两个超时参数均不设置。所有为了允许抢占容器,需要至少设置其中一个超时参数。
  如果队列在最小共享指定的时间内未获得被承诺的最小共享资源,调度器就会抢占其他容器。可以通过分配文件中的顶层元素defaultMinSharePreemptionTimeout为所有队列设置默认的超时时间,还可以通过设置每个队列的minSharePreemptionTimeout元素来为单个队列指定超时时间。
  如果队列在公平共享指定的时间内未获得的资源仍然低于其公平共享份额的一半,那么调度器就会抢占其他容器。可以通过分配文件中的顶层元素defaultFairSharePreemptionTimeout为所有队列设置默认的超时时间,还可以通过设置每个队列的fairSharePreemptionTimeout元素来为单个队列指定超时时间。通过设置defaultFairSharePreemptionThreshold和fairSharePreemptionThreshold(针对每个队列)可以修改超时阈值,默认值是0.5。

延迟调度

所有的YARN调度器都试图以本地请求为重。在一个繁忙的集群上,如果一个应用请求某个节点,那么极有可能此时有其他容器正在该节点上运行,显而易见的处理是,like放款本地性需求,在同一机架上分配一个容器,然而,通过实践发现,此时如果等待一小段实践(不超过几秒),能够戏剧性的增加在所请求的节点上分配到一个容器的机会,从而可以提高集群的效率。这个特性称之为延迟调度(delay scheduling)。容量调度器和公平调度器都支持延迟调度。
  YARN中的每个节点管理器周期性的(默认每秒一次)向资源管理器发送心跳请求。心跳中携带了节点管理器中正运行的容器、新容器可用的资源等信息,这样对于一个计划运行一个容器调度应用而言,每个心跳就是一个潜在的调度机会(scheduling opportunity)。
  当使用延迟调度器,可以通过设置yarn.scheduler.capacity.node-locality-delay来配置延迟调度。设置为正数,表示调度器在放松节点限制、改为匹配同一机架上的其他节点前,准备错过的调度机会的数量。
  公平调度器也使用调度机会的数量来决定延迟时间,尽管是使用集群规模的比例来表示这个值,例如将yarn.sheduler.fair.locality.threshold.node设置为0.5,表示调度器在接收同一机架上的其他节点前,将一直等待指导集群中的一半节点都已经给过调度机会。还有相关的属性yarn.sheduler.fair.locality.threhold.rack,表示在接收另一个机架替代所申请的机架之前需要等待的时长阈值。

主导资源公平性

对于单一类型资源,如内存的调度,容量或公平性的概念很容易确定。如果两个用户正在运行应用,可以通过度量每个应用使用的内存来比较两个应用。当有多重资源类型需要调度时,事情就会变得复杂。例如,如果一个用户的应用对CPU的需求量很大,但对内存的需求量很少;而另一个用户的应用需要很少的CPU,但对内存需求量很大,那么如何比较这两个应用呢?
  YARN中调度器解决这个问题的思路是,观察每个用户的主导资源,并将其作为对集群资源使用的一个度量,这个方法称为“主导资源公平性”(Dominant Resource Fairness,DRF)。这个思想用一个简单的例子就可以很好的给予解释。
  想象一个总共100个CPU和10TB的集群。应用A请求的每份容器资源为2个CPU和300G内存,用用B请求的每份容器资源为6个CPU和100G内存。A请求的资源在集群资源中占比分别为2%和3%,由于内存占比(3%)大于CPU占比(2%),所有内存是A的主导资源。B请求的资源在集群资源中占比分别为6%和1%,所有CPU是B的主导资源。由于B申请的资源是A的两倍(6%vs3%),所以在公平调度下,B将分到一半的容器数。
  默认情况下不用DRF,因此在资源计算期间,只需要考虑内存,不必考虑CPU。对容器调度器进行配置后,可以使用DRF,将capacity-scheduler.xml文件中的org.apache.hadoop.yarn.util.resource.DominantResourceCalculator设为yarn.scheduler.capacity.resource-calculator即可。
  公平调度器若要使用DRF,通过将分配文件中的顶层元素defaultQueueSchudulingPolicy设为drf即可。

猜你喜欢

转载自blog.csdn.net/maydaysar/article/details/82747073