Apache YARN(Yet Another Resource Negotiator,另一种资源协调者)是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处。
概述
Apache YARN(Yet Another Resource Negotiator,另一种资源协调者)是 Hadoop 的集群资源管理系统。YARN 被引入 Hadoop 2,最初是为了改善 MapReduce 的实现,但它具有足够的通用性,同样可以支持其他的分布式计算模式。
YARN 提供请求和使用集群资源的 API,但这些 API 很少直接用于用户代码。用户代码中用的是分布式计算框架(MapReduce,Spark 等)提供的更高层 API,这些分布式计算框架的 API 建立在 YARN 之上,作为 YARN 应用运行在集群计算层(YARN)和集群存储层(HDFS 和 HBase)上。至于 Hive 则是运行在 MapReduce 或 Spark 之上的处理框架,不与 YARN 直接打交道。
架构
YARN 的基本思想是将资源管理和作业调度/监控的功能拆分为单独的守护进程。YARN 主要由 ResourceManager、NodeManager、ApplicationMaster 和 Container 等几个组件构成:
- ResourceManager 负责全局资源的监控、分配和管理,是在系统中所有应用程序之间仲裁资源的最终权威;
- NodeManager 负责每一个节点的维护,负责容器、监控其资源使用情况(CPU、内存、磁盘、网络)并将其报告给 ResourceManager/Scheduler;
- ApplicationMaster 负责每一个具体应用程序的调度,协商来自 ResourceManager 的资源并与 NodeManager 一起执行和监视任务;
- Container 是 YARN 中分配资源的一个单位,包含了内存、CPU 等资源。
不同模块之间的关系如图:
ResourceManager
- ResourceManager 负责整个集群的资源管理和分配,是一个全局的资源管理系统。
- ResourceManager 主要有两个组件:Scheduler 和 ApplicationsManager
- Scheduler 主要负责协调集群中各个应用的资源分配,保障整个集群的运行效率。它是一个纯粹的资源调度器,不执行应用程序的状态监视或跟踪,也不能重启运行失败的任务。
- ApplicationsManager 负责接收提交的作业,为应用程序分配第一个容器来运行 ApplicationMaster,并提供在失败时重新启动 ApplicationMaster 容器的服务。每个应用程序的 ApplicationMaster 负责与调度程序协商适当的资源容器,跟踪它们的状态并监视进度。
- NodeManager以心跳的方式向ResourceManager汇报资源使用情况(目前主要是CPU和内存的使用情况)。RM只接受NM的资源回报信息,对于具体的资源处理则交给NM自己处理。
- YARN Scheduler根据application的请求为其分配资源,不负责application job的监控、追踪、运行状态反馈、启动等工作。
NodeManager
- NodeManager是每个节点上的资源和任务管理器,它是管理这台机器的代理,负责该节点程序的运行,以及该节点资源的管理和监控。YARN集群每个节点都运行一个NodeManager。
- NodeManager定时向ResourceManager汇报本节点资源(CPU、内存)的使用情况和Container的运行状态。当ResourceManager宕机时NodeManager自动连接RM备用节点。
- NodeManager接收并处理来自ApplicationMaster的Container启动、停止等各种请求。
ApplicationMaster
- 用户提交的每个应用程序均包含一个ApplicationMaster,它可以运行在ResourceManager以外的机器上。
- 负责与RM调度器协商以获取资源(用Container表示)。
- 将得到的任务进一步分配给内部的任务(资源的二次分配)。
- 与NM通信以启动/停止任务。
- 监控所有任务运行状态,并在任务运行失败时重新为任务申请资源以重启任务。
- 当前YARN自带了两个ApplicationMaster实现,一个是用于演示AM编写方法的实例程序DistributedShell,它可以申请一定数目的Container以并行运行一个Shell命令或者Shell脚本;另一个是运行MapReduce应用程序的AM—MRAppMaster。
- 注:RM只负责监控AM,并在AM运行失败时候启动它。RM不负责AM内部任务的容错,任务的容错由AM完成。
运行机制
YARN 通过两类长期运行的守护进程提供自己的核心服务:
- ResourceManager:资源管理器,管理集群上资源的使用。
- NodeManager:节点管理器,运行在集群中所有节点上,能够启动和监控容器。
相关概念:
- Container:容器,用于执行特定应用程序的进程,每个容器都会分配一定的资源(内存,CPU 等)。
- ApplicationMaster:负责计算任务的监控与控制,由计算框架实现。
YARN 应用的运行机制如下:
- Client 向 ResourceManager 提交应用程序,要求它运行一个 ApplicationMaster 进程(步骤 1)。
- ResourceManager 找到一个能够在容器中启动 ApplicationMaster 的 NodeManager(步骤 2)。ApplicationMaster 在启动时向 ResourceManager 注册自己,启动成功后与 ResourceManager 保持心跳。
- ApplicationMaster 运行起来后,根据应用本身的需求:可以在所在容器简单地运行一个计算,并将结果返回给客户端;或是向 ResourceManager 请求更多的容器(步骤 3),以用于运行一个分布式计算(步骤 4a 和 4b):
- 申请成功的容器由 ApplicationMaster 进行初始化,并与容器所在的 NodeManager 进行通信,要求启动容器。
- ApplicationMaster 与 NodeManager 保持心跳,从而对 NodeManager 上运行的任务进行监控和管理。
- 应用运行期间,Client 直接与 ApplicationMaster 通信获取应用的状态信息。
- 应用运行结束,ApplicationMaster 向 ResourceManager 注销自己,允许属于它的容器被收回。
对比MapReduce1
此处的 MapReduce 1 指代 Hadoop 初始版本中的 MapReduce 分布式执行框架。
MapReduce 1 有两类守护进程控制着作业执行过程:
- JobTracker:通过调度 TaskTracker 上运行的任务来协调所有运行在系统上的作业;记录每项作业任务的整体进度情况;如果其中一个任务失败,可以在另一个 TaskTracker 上重新调度该任务。
- TaskTracker:执行 JobTracker 分配的计算任务,在运行的同时将运行进度报告发送给 JobTracker。
在 MapReduce 1 中,JobTracker 同时负责作业调度和任务进度监控。而在 YARN 中,这些职责分别交由 ResourceManager 和 ApplicationMaster 分担。而 MapReduce 1 中的 TaskTracker 的角色由 YARN 中的 NodeManager 担当。
MapReduce 1 | YARN |
---|---|
JobTracker | ResourceManager,ApplicationMaster,时间轴服务器(存储作业历史) |
TaskTracker | NodeManager |
Slot | Container |
YARN 的很多设计是为了解决 MapReduce 1 的局限性,带来的好处包括以下几个方面:
- 可扩展性:YARN 可以在更大规模的集群上运行。MapReduce 1 的瓶颈在于其 JobTracker 必须同时负责作业调度和任务进度监控,而在 YARN 上交由 ResourceManager 和 AppleMaster 分担。
- 可用性:JobTracker 内存中大量快速变化的复杂状态使得其获得高可用性非常困难,而 YARN 将其分而治之,先为 ResourceManager 提供高可用性,再为每个 YARN 应用提供高可用性。
- 利用率:MapReduce 1 中每个 TaskTracker 配置若干固定长度的 Slot,这些 Slot 被划分为 Map Slot 和 Reduce Slot,只能运行对应的 Map 任务或 Reduce 任务;YARN 中的资源是精细化管理的,不指定固定数目的 Slot,应用能够按需请求资源。
- 多租户:YARN 向 MapReduce 以外的其他类型分布式应用开放了 Hadoop,而 MapReduce 仅仅是许多 YARN 应用中的一个。
调度器
集群的资源是有限的,在一个繁忙的集群上,一个应用经常需要等待才能得到所需的资源。YARN 调度器的工作就是根据既定策略为应用分配资源。调度是一个难题,没有所谓“最好”的策略,因此 YARN 提供了多种调度器和配置策略供我们选择。
YARN 中有三种调度器可用:
- FIFO 调度器(FIFO Scheduler):将所有应用放置在一个队列中,按照提交的顺序运行应用。无需配置,但不适合共享集群。大的应用会占用集群的所有资源,每个应用必须等到轮到自己运行。
- 容量调度器(Capacity Scheduler):大的应用放在主队列中执行,另有一个独立的专门队列保证小作业一提交就可以启动。由于一直为专门队列保留了部分资源,牺牲了整个集群的利用率,大作业执行时间相比 FIFO 调度器要长。
- 公平调度器(Fair Scheduler):不需要预留一定量的资源,调度器会在所有运行的作业之间动态平衡资源。第一个作业启动时,会获得集群中所有的资源;第二个作业启动时,会被分配到集群一半的资源。这样每个作业都能公平共享资源。第二个作业从启动到获得公平共享资源之间有时间滞后,因为必须等待第一个作业使用的容器用完并释放出资源。既得到了较高的集群利用率,又能保证小作业能及时完成。
调度器的选择是通过 yarn-site.xml
中的 yarn.resourcemanager.scheduler.class
来设置的,Apache Hadoop 默认使用容量调度器,CDH 默认使用公平调度器。需要填入调度器对应的完全限定名:
1 | org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler |
容量调度器
容量调度器允许多个组织共享一个 Hadoop 集群,每个组织配置一个专门的队列,可以分配到一部分集群资源。队列可以进一步按层次划分, 每个组织内的不同用户能够共享该组织队列所分配的资源。在一个队列内,使用 FIFO 调度策略对应用进行调度。
弹性队列:单个作业使用的作业不会超出其队列容量。然而,如果队列中有多个作业,并且队列资源不够,如果集群仍有空闲资源,容量调度器可能会将空闲资源分配给队列中的作业,哪怕超出队列容量。
限制最大容量:容量调度器在正常情况下不会通过强行终止来抢占容器。因此,一个队列会随着需求增长影响到其他队列的作业。为队列设置一个最大容量限制,这样这个队列就不会过多侵占其他队列的容量了。当然,这样会牺牲队列弹性。
队列配置
创建容量调度器配置文件 capacity-scheduler.xml
,实现以下效果:
- 在
root
队列下定义prod
和dev
两个队列,分别占 40% 和 60% 的容量。其中dev
队列的最大容量为 75%,而prod
队列可以占用全部资源。 dev
队列进一步被划分为eng
和science
两个容量相等的队列。
队列层次结构如下:
1 | root |
队列是通过属性 yarn.sheduler.capacity.<queue-path>.<sub-property>
进行设置的:
<queue-path>
表示队列的层次路径,用.
隔开。<sub-property>
常用的参数有以下几个:capacity
:队列的资源容量(百分比)。maximum-capacity
:队列的资源上限(百分比)。state
:队列的状态。RUNNING
表示正常运行;STOPPED
表示停止工作,不可再提交应用,正在运行的应用可以正常运行结束。
配置文件如下:
1 |
|
队列放置
将应用放置在哪个队列取决于应用本身。比如 MapReduce 中可以通过设置属性 mapreduce.job.queuename
来指定要用的队列;如果队列不存在,则在提交时会发送错误;如果不指定,应用将被放进名为 default
的默认队列中。
公平调度器
公平调度器旨在为所有的应用分配公平的资源。调度器会在所有运行的作业之间动态平衡资源。第一个作业启动时,会获得集群中所有的资源;第二个作业启动时,会被分配到集群一半的资源。这样每个作业都能公平共享资源。
队列配置
公平调度器是通过分配文件 fair-scheduler.xml
来进行配置的。在没有分配文件时,公平调度器的工作策略如下:每个应用程序都放置在一个以用户命名的队列中,队列是在用户提交第一个应用时动态创建的。
在分配文件中可以为每个队列进行配置,这样可以对容量调度器支持的层次队列进行配置:
1 |
|
队列层次使用嵌套 queue
元素来定义。所有队列都是 root
队列的孩子,哪怕实际上没有嵌套进 root queue
元素中。这里把 dev
队列又划分成 eng
和 science
两个队列。
队列中有权重元素 weight
,用于共享计算。在该示例中,当集群按照 40:60 的比例分配给 prod
和 dev
时,该分配被认为是公平的。eng
和 science
队列没有指定权重,会被平均分配。weight
不是用百分比表示,指定为 2
和 3
在效果上是一样的。
每个队列可以有不同的调度策略。队列的默认策略可以通过顶层元素 defaultQueueSchedulingPolicy
进行设置,默认使用公平调度 fair
,但也支持队列级别的 fifo
策略,比如 prod
队列就使用了 fifo
策略,以便进入该队列的每个生产性作业能够顺序运行且尽可能的最短时间内结束。
队列放置
公平调度器使用一个基于规则的系统来确定应用该放到哪个队列。queuePlacementPolicy
元素包含了一个规则列表,每条规则会被依次尝试直到匹配成功:
specified
:表示把应用放进所指定的队列中,如果没有指定或指定的队列不存在,则继续尝试下一条规则。primaryGroup
:试着把应用放在以用户的主 Unix 组名命名的队列中,如果没有,则继续尝试下一条规则。default
:如果以上规则都不匹配,启用这条规则,把应用放进dev.eng
队列中。
如果省略 defaultQueueSchedulingPolicy
元素,此时队列放置默认遵从以下规则:
1 | <queuePlacementPolicy> |
此时,如果没有明确定义队列,会以用户名为队列名创建队列。
将属性 yarn.scheduler.fair.user-as-default-queue
设置为 false
,应用会被放入 default
队列,而不是各个用户的队列。
将属性 yarn.scheduler.fair.allow-underclared-pools
设置为 false
,用户便不能随意创建队列了。
YARN 架构 https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/YARN.html