我们前面篇章有提到,和MapReduce的论文不太一样。在Hadoop1.0实现里,每一个MapReduce的任务并没有一个独立的master进程,而是直接让调度系统承担了所有的worker 的master 的角色,这就是Hadoop1.0里的 JobTracker。在Hadoop1.0里,MapReduce论文里面的worker就是TaskTracker,用来执行map 和 reduce的任务。而分配任务,以及和TaskTracker沟通任务的执行情况,都由单一的JobTracker 来负责。
这样实现的好处是比较简单,相对的,导致了JobTracker的负载过重,成为了整个Hadoop 系统“瓶颈”。在Hadoop 2.0,Hadoop社区把JobTracker的角色,拆分成了进行任务调度的Resource Mananger,以及监控单个MapReduce任务执行的Application Master,回到了和MapReduce论文相同的架构。
Hadoop 能有今天这个地位,Yarn可以说是功不可没。因为有了 Yarn ,更多计算框架可以接入到 HDFS 中,而不单单是 MapReduce,MapReduce 早已经被 Spark 等计算框架赶超,而 HDFS 却依然屹立不倒。究其原因,正式因为 Yarn 的包容,使得其他计算框架能专注于计算性能的提升。HDFS 可能不是最优秀的大数据存储系统,但却是应用最广泛的大数据存储系统,Yarn 功不可没。
今天我们来看看关于Yarn的涉及与实现。
Yarn是“Yet Another Resource Negotiator”的缩写,字面意思就是“另一种资源调度器”。
事实上,在Hadoop社区决定将资源管理从Hadoop 1中分离出来,独立开发Yarn的时候,业界已经有一些大数据资源管理产品了,比如Mesos等,所以Yarn的开发者索性管自己的产品叫“另一种资源调度器”。这种命名方法并不鲜见,曾经名噪一时的Java项目编译工具Ant就是“Another Neat Tool”的缩写,意思是“另一种整理工具”。
YARN的基本设计思想是将JobTracker拆分成两个独立的服务:一个全局的资源管理器ResourceManager和每个应用程序特有的ApplicationMaster。其中,ResourceManager负责整个系统的资源管理和分配,而ApplicationMaster则负责单个应用程序的管理。
YARN总体上仍然是master/slave结构。在整个资源管理框架中,ResourceManager为master,NodeManager为slave,ResourceManager负责对各个NodeManager上的资源进行统一管理和调度。
当用户提交一个应用程序时,需要提供一个用于跟踪和管理这个程序的ApplicationMaster。它负责向ResourceManager申请资源,并要求NodeManager启动可以占用一定资源的任务。由于不同的ApplicationMaster分布在不同的节点上,因此它们之间不会相互影响。
整个系统有且只有一个 ResourceManager ,它是基于应用程序对集群资源的需求进行调度的 Yarn 集群主控节点,负责协调和管理整个集群的资源,处理客户端请求、启动/监控ApplicationMaster、监控NodeManager、资源分配与调度。
它包含了两个主要的组件:调用器(Scheduler)以及应用管理器(ApplicationsManager,ASM)。
调度器(Scheduler)
调度器根据容量、队列等限制条件(如每个队列分配一定的资源,最多执行一定数量的作业等),将系统中的资源分配给各个正在运行的应用程序。
从本质上来说,定时调度器就是一个资源分配算法(或者说是一种策略)。当 Client 提交一个任务的时候,它会根据所需要的资源以及当前集群的资源状况进行分配。
注意:
它只负责向应用程序分配资源,并不负责监控或者跟踪应用的执行状态等,也不负责重新启动因应用执行失败或者硬件故障而产生的失败任务。
调度器被设计成一个可插拔的组件,用户可根据自己的需要设计新的调度器,YARN提供了多种直接可用的调度器,比如
Fair Scheduler
和Capacity Scheduler
等。
应用管理器(ApplicationsManager)
应用程序管理器负责管理整个系统中所有应用程序,包括应用程序提交、与调度器协商资源以启动ApplicationMaster、监控ApplicationMaster运行状态并在失败时重新启动它等。
具体职责包括:
应用程序提交:
接收客户端提交的应用程序请求。
验证应用程序的配置和资源请求。
资源分配:
根据集群的资源情况和调度策略,分配资源给各个应用程序。
启动应用程序的第一个容器,即 ApplicationMaster 容器。
监控应用程序:
监控应用程序的运行状态。
处理应用程序的完成、失败和重试等情况。
维护应用程序队列:管理应用程序队列,确保资源分配的公平性和高效性。
AM是每个应用程序的专属组件,负责管理该应用程序的具体执行。用户提交的每个应用程序在启动时都会有一个独立的 AM。
它实际上是一个简化版的JobTracker,主要功能包括:
与RM调度器协商以获取资源。
与NM通信以启动/停止任务。
监控所有任务的运行状态,并在任务运行失败时重新为任务申请资源以重启任务。
ApplicationMaster负责数据切分、为应用程序申请资源,并分配给内部任务、任务监控与容错 每当 Client 提交一个 Application 时候,就会新建一个 ApplicationMaster 。由这个ApplicationMaster 去与 ResourceManager 申请容器资源,获得资源后会将要运行的程序发送到容器上启动,然后进行分布式计算。(也就是所谓的移动计算)
具体职责包括:
资源请求:
向 ResourceManager 请求资源,以运行应用程序的任务。
根据应用程序的需求,动态调整资源请求。
任务调度和监控:
将获得的资源分配给具体的任务(Task)。
启动和监控任务的执行,处理任务的失败和重试。
任务协调:
协调应用程序的所有任务,确保任务按计划执行。
收集任务的执行结果,并进行必要的合并和处理。
状态报告:
向 ResourceManager 报告应用程序的运行状态和进度。
在应用程序完成时,通知 ResourceManager 释放资源。
ASM和AM的区别
- ApplicationsManager(ResourceManager 的一部分);
- 管理整个集群中的应用程序生命周期;
- 负责资源分配、应用程序提交和监控;
- 启动 ApplicationMaster 容器。
ApplicationMaster:
- 每个应用程序的专属组件,管理该应用程序的具体执行;
- 负责资源请求、任务调度和监控、任务协调和状态报告;
- 动态调整资源请求,确保应用程序的高效执行。
总结:ApplicationsManager 负责全局资源管理和调度,而 ApplicationMaster 负责具体应用程序的执行和协调。
NM是每个节点上的资源和任务管理器。
它会定时地向RM汇报本节点上的资源使用情况和各个Container的运行状态;
它接收并处理来自AM的任务启动/停止等各种请求。
NodeManager 是 YARN 集群当中真正资源的提供者,是真正执行应用程序的容器的提供者, 监控应用程序的资源使用情况,并通过心跳向集群资源调度器 ResourceManager 进行汇报,处理来自ResourceManager和ApplicationMaster的命令。
Container是YARN中的资源分配单位,它封装了多维度的资源,如内存、CPU、磁盘、网络等。当AM向RM申请资源时,RM为AM返回的资源便是用Container表示的。YARN中每个任务均会对应一个Container,且该任务只能在该Container中执行,并仅能使用该容器代表的资源量。需要注意的是,Container不同于MRv 1中的slot,它是一个动态资源划分单位,是根据应用程序的需求动态生成的。
Container 是一个抽象出来的逻辑资源单位。它对任务运行环境的抽象,封装了内存、CPU、磁盘、网络等多维资源以及环境变量、启动命令等任务运行相关的信息,当AM向RM申请资源时,RM为AM返回的资源便是用Container表示的。
YARN中每个任务均会对应一个Container,且该任务只能在该Container中执行,并仅能使用该Container代表的资源量。
注意:Container不同于MRv1中的slot,它是一个动态资源划分单位,是根据应用程序的需求动态生成的。
Container是 Yarn 对资源做的一层抽象。就像我们平时开发过程中,经常需要对底层一些东西进行封装,只提供给上层一个调用接口一样,Yarn 对资源的管理也是用到了这种思想。 Yarn 将CPU核数,内存这些计算资源都封装成为一个个Container。
当用户向YARN中提交一个应用程序后,YARN将分两个阶段运行该应用程序:
第一个阶段是启动ApplicationMaster;
第二个阶段是由ApplicationMaster创建应用程序,为它申请资源,并监控它的整个运行过程,直到运行成功。
用户向 YARN 中提交应用程序,其中包括 ApplicationMaster 程序,启动 ApplicationMaster 的命令,用户程序等
ResourceManager 为该程序分配第一个 Container,并与对应的 NodeManager 通讯,要求它在这个 Container 中启动应用程序 ApplicationMaster
ApplicationMaster 首先向 ResourceManager注册,这样用户可以直接通过 ResourceManager 查看应用程序的运行状态,然后将为各个任务申请资源,并监控它的运行状态,直到运行结束,重复 4 到 7 的步骤
ApplicationMaster 采用轮询的方式通过 RPC 协议向 ResourceManager 申请和领取资源
一旦 ApplicationMaster 申请到资源后,便与对应的 NodeManager 通讯,要求它启动任务
NodeManager为任务设置好运行环境(包括环境变量、jar包、二进制程序等)后,将任务启动命令写到一个脚本中,并通过运行该脚本启动任务。
各个任务通过某个RPC协议向ApplicationMaster汇报自己的状态和进度,以让ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务。
在应用程序运行的过程中,用户可随时通过RPC协议向ApplicationMaster查询应用程序的当前运行状态。
应用程序运行完成后,ApplicationMaster 向 ResourceManager 注销并关闭自己。
在YARN中,任何两个需相互通信的组件之间仅有一个RPC协议,而对于任何一个RPC协议,通信双方有一端是Client,另一端为Server,且Client总是主动连接Server,因此,YARN实际上采用的是拉式(pull-based)通信模型,主要有以下几个RPC协议:
注意:
为了提高Hadoop的向后兼容性和不同版本之间的兼容性,YARN中的序列化框架采用了Google开源的Protocol Buffers。
关于RPC可以看这篇文章。
Hadoop作业调度器主要有三种:FIFO、Capacity Scheduler和Fair Scheduler。
Yarn中FIFO、Capacity、Fair三种资源调度器区别对比如下:
Yarn资源调度器 |
特点 |
适用场景 |
---|---|---|
FIFO调度器 |
1)简单易懂,无需额外配置。 |
非共享集群,对任务执行顺序要求不高的场景。生产环境一般不用。 |
Capacity调度器(开源Yarn默认使用) |
1)允许多个组织共享集群资源,每个组织拥有专门的队列。 |
共享集群的场景,多个组织或团队共享同一集群资源的情况。 |
Fair调度器(CDH默认使用) |
1)公平地为所有运行的应用分配资源,支持多个队列间的资源公平共享。 |
1) 多个用户或组织在共享集群中需要公平地获得资源的场景。 |
Hadoop2.x默认的资源调度器是Capacity Scheduler。(可以查看yarn-default.xml)
Yarn中最简单的调度器。FIFO Scheduler 会将提交的应用程序按提交顺序放入一个先进先出的队列中,进行资源分配时,先给队列中最头上的应用分配资源,待头上的应用资源需求满足后再给下一个应用分配资源,以此类推。这种调度器调度资源时,有可能某个资源需求大的应用占用所有集群资源,从而导致其他的应用被阻塞。
FIFO调度器只支持单队列,先进队列的任务先获取资源,排在后面的任务只能等待,不能同时保证其他任务获取运行资源,这种调度器很少使用。
Yarn中默认配置的资源调度器,允许多租户安全地共享一个大型集群。Capacity调度器中,支持配置多个资源队列,可以为每个资源队列指定最低、最高可使用的资源比例,在进行资源分配时,优先将空闲资源分配给“实际资源/预算资源”比值最低的队列,每个资源队列内部采用FIFO调度策略。
Capacity调度器的核心思想是提前做预算,在预算指导下分享集群资源。其特点如下:
Capacity资源分配策略
Capacity Scheduler调度器中如果有多个资源队列,这些个资源队列进行资源分配时优先分配给“实际资源/预算资源”比值最低的队列。每个队列中有多个Job,给每个队列内的多个Job进行资源分配时,默认按照Job的FIFO顺序进行资源分配,用户也可以提交JOB时指定任务执行的优先级,优先级最高的先分配资源。
一个将Yarn资源公平的分配给各个Application的资源调度方式,这种调度方式可以使所有Application随着时间的流逝可以获取相等的资源份额,其设计目标就是根据定义的参数为所有的Application分配公平的资源。
FairScheduler资源调度核心思想就是通过资源平分的方式,动态分配资源,无需预先设定资源比例,实现资源分配公平,其特点如下:
Fair资源分配策略
Fair Scheduler支持多资源队列,每个资源队列进行资源调度时按照配置指定的权重平均分配资源。在每个资源队列中job的资源调度策略有三种选择:FIFO、Fair(默认)、DRF,这三种Job调度策略解释如下。
备注:DFR(Dominant Resource Fairness,主导资源公平性)。
在Yarn中如果进行资源调度时只考虑单一资源类型,如内存,那么这个事情就很简单,只需要将不同资源队列/Job按它们使用的内存量比例进行调度资源即可,FIFO/Fair就是只基于内存进行资源调度分配。然而当涉及多个资源类型时,情况就变得复杂,例如:一个用户的Application需要大量的CPU但使用很少内存,而另一个用户的Application需要很少的CPU但大量的内存,这里不能仅考虑内存比值来进行资源调度分配,否则可能出现资源分配不合理情况,这种情况除了内存之外还要考虑Application的Vcore使用情况,这就可以使用DRF资源分配策略。
DRF(Dominant Resource Fairness,资源分配策略中,会查看每个Application中主导资源(Dominant Resource)是什么,并将其作为集群调度资源的衡量标准。例如:yarn集群中共100个CPU和10TB内存,应用程序A请求容器(2个CPU,300GB内存),应用程序B请求容器(6个CPU,100GB内存)。A的请求是集群的(2%,3%),所以内存是主导资源,B的请求是集群的(6%,1%),所以CPU是主导资源,由于B程序的容器请求主要资源是A程序容器请求主要资源的2倍(6%/3%=2),所以在DRF资源分配策略下,B程序最大可使用在集群2/3资源。
今天梳理了关于Yarn的核心设计与实现,由于要回老家过年了,笔记本不太方便捋源码,MR和Yarn的深入源码分析文章就暂时延后到年后回来再写。
我们目前见识了很多大数据技术的设计与实现,会发现有很多类似的设计,甚至可以用“新瓶装旧酒”来形容。无论大数据技术如何变化,不变的是那些凝结了人类历史知识和经验的技术精华,过年这几天我会专门开一个基础专题系列,让我们重点看一下这些技术精华是什么。
最后,提前祝大家新年快乐