一. Yarn架构
1.1 简介
1.1.1 架构
YARN主要由ResourceManager、NodeManager、ApplicationMaster和Container等几个组件构成。
YARN总体上仍然是Master/Slave结构,在整个资源管理框架中,ResourceManager为Master,NodeManager为Slave,ResourceManager负责对各个NodeManager上的资源进行统一管理和调度。当用户提交一个应用程序时,需要提供一个用以跟踪和管理这个程序的ApplicationMaster,它负责向ResourceManager申请资源,并要求NodeManger启动可以占用一定资源的任务。由于不同的ApplicationMaster被分布到不同的节点上,因此它们之间不会相互影响。
1.1.2 Job提交流程
- 用户向YARN中提交应用程序,其中包括ApplicationMaster程序、启动ApplicationMaster的命令、用户程序等。
- ResourceManager为该应用程序分配第一个Container,并与对应的Node-Manager通信,要求它在这个Container中启动应用程序的ApplicationMaster。
- ApplicationMaster首先向ResourceManager注册,这样用户可以直接通过ResourceManager查看应用程序的运行状态,然后它将为各个任务申请资源,并监控它的运行状态,直到运行结束,即重复步骤4~7。
- ApplicationMaster采用轮询的方式通过RPC协议向ResourceManager申请和领取资源。
- 一旦ApplicationMaster申请到资源后,便与对应的NodeManager通信,要求它启动任务。
- NodeManager为任务设置好运行环境(包括环境变量、JAR包、二进制程序等)后,将任务启动命令写到一个脚本中,并通过运行该脚本启动任务。
- 各个任务通过RPC协议向ApplicationMaster汇报自己的状态和进度,以便让ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务。在应用程序运行过程中,用户可随时通过RPC向ApplicationMaster查询应用程序的当前运行状态。
- 应用程序运行完成后,ApplicationMaster向ResourceManager注销并关闭自己。
1.2 组件介绍
1.2.1 ResourceManager(RM)
RM 是一个全局的资源管理器,负责整个系统的资源管理和分配。它主要由两个组件构成:调度器(Scheduler)和应用程序管理器(Applications Manager)。
调度器(Scheduler)
调度器根据容量、队列等限制条件(如每个队列分配一定的资源,最多执行一定数量的作业等),将系统中的资源分配给各个正在运行的应用程序。
需要注意的是,该调度器是一个“纯调度器”,它不再从事任何与具体应用程序相关的工作,比如不负责监控或者跟踪应用的执行状态等,也不负责重新启动因应用执行失败或者硬件故障而产生的失败任务,这些均交由应用程序相关的ApplicationMaster完成。调度器仅根据各个应用程序的资源需求进行资源分配,而资源分配单位用一个抽象概念“资源容器”(Resource Container,简称Container)表示,Container是一个动态资源分配单位,它将内存、CPU、磁盘、网络等资源封装在一起,从而限定每个任务使用的资源量。此外,该调度器是一个可插拔的组件,用户可根据自己的需要设计新的调度器。
在Yarn中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,Fair Scheduler。
FIFO Scheduler
FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。
Capacity Scheduler
Capacity 调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。除此之外,队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
在正常的操作中,Capacity调度器不会强制释放Container,当一个队列资源不够用时,这个队列只能获得其它队列释放后的Container资源。当然,我们可以为队列设置一个最大资源使用量,以免这个队列过多的占用空闲资源,导致其它队列无法使用这些空闲资源,这就是”弹性队列”需要权衡的地方。
配置方法:
Capacity调度器的配置文件,文件名为capacity-scheduler.xml
# 例如以下队列 root ├── prod 40% └── dev 60% ~ 75% ├── eng 50% └── science 50%
上面队列配置如下:
<?xml version="1.0"?> <configuration> <!-- 定义了两个子队列prod和dev --> <property> <name>yarn.scheduler.capacity.root.queues</name> <value>prod, dev</value> </property> <!-- dev队列又被分成了eng和science --> <property> <name>yarn.scheduler.capacity.root.dev.queues</name> <value>eng, science</value> </property> <!-- 队列prod占40%的容量 --> <property> <name>yarn.scheduler.capacity.root.prod.capacity</name> <value>40</value> </property> <!-- 队列dev占60%的容量 --> <property> <name>yarn.scheduler.capacity.root.dev.capacity</name> <value>60</value> </property> <!-- 限制dev的最大资源伸缩比重为75%,所以即使prod队列完全空闲dev也不会占用全部集群资源 --> <property> <name>yarn.scheduler.capacity.root.dev.maximum-capacity</name> <value>75</value> </property> <!-- 队列eng占50%的容量,由于没有设置最大值,所以可能占用整个父队列的资源 --> <property> <name>yarn.scheduler.capacity.root.dev.eng.capacity</name> <value>50</value> </property> <!-- 队列science占50%的容量,由于没有设置最大值,所以可能占用整个父队列的资源 --> <property> <name>yarn.scheduler.capacity.root.dev.science.capacity</name> <value>50</value> </property> </configuration>
Capacity容器除了可以配置队列及其容量外,我们还可以配置一个用户或应用可以分配的最大资源数量、可以同时运行多少应用、队列的ACL认证等。
在MapReduce中,我们可以通过mapreduce.job.queuename属性指定要用的队列。如果队列不存在,我们在提交任务时就会收到错误。如果我们没有定义任何队列,所有的应用将会放在一个default队列中。
注意:对于Capacity调度器,我们的队列名必须是队列树中的最后一部分,如果我们使用队列树则不会被识别。即不能写成dev.eng,应该写为eng。
Fair Scheduler
Fair调度器的设计目标是为所有的应用分配公平的资源(对公平的定义可以通过参数来设置)。举个例子,假设有两个用户A和B,他们分别拥有一个队列。当A启动一个job而B没有任务时,A会获得全部集群资源;当B启动一个job后,A的job会继续运行,不过一会儿之后两个任务会各自获得一半的集群资源。如果此时B再启动第二个job并且其它job还在运行,则它将会和B的第一个job共享B这个队列的资源,也就是B的两个job会用于四分之一的集群资源,而A的job仍然用于集群一半的资源,结果就是资源最终在两个用户之间平等的共享。
# 启用Fair调度器 # yarn-site.xml中配置 <property> <name>yarn.resourcemanager.scheduler.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value> </property> # 队列的配置 # 配置文件为fair-scheduler.xml # 可以通过下面配置修改配置文件路径(yarn-site.xml中) <property> <name>yarn.scheduler.fair.allocation.file</name> <value>xxxxx</value> </property> # fair-scheduler.xml配置例 <?xml version="1.0"?> <allocations> <!-- 默认调度策略,如果没有配置这项,默认fair --> <defaultQueueSchedulingPolicy>fair</defaultQueueSchedulingPolicy> <queue name="prod"> <!-- 权重,如果没有配置默认为1 --> <weight>40</weight> <schedulingPolicy>fifo</schedulingPolicy> </queue> <queue name="dev"> <weight>60</weight> <queue name="eng"/> <queue name="science"/> </queue> <!-- queuePlacementPolicy元素定义规则列表,会逐个尝试直到匹配成功。 第一个规则specified,则会把应用放到它指定的队列中,若这个应用没有指定队列或队列名不存在,则不匹配这个规则; primaryGroup规则会尝试把应用以用户所在的Unix组名命名的队列中,如果没有这个队列,不创建队列转而尝试下一个; 当前面所有规则不满足时,则触发default规则,把应用放在dev.eng队列中 --> <queuePlacementPolicy> <rule name="specified" create="false"/> <rule name="primaryGroup" create="false"/> <rule