资源调度器是 Hadoop Yarn 中最核心的组件之一。是 ResourceManager 中的一个插拔式服务组件,负责整个集群资源的管理和分配。
Yarn 提供了三种可用资源调度器:FIFO(先到先得),Capacity Scheduler(计算能力调度器),Fair Scheduler(公平调度器)。
资源调度器的发展
Hadoop 最初的设计是支持大数据批量作业,提供了非常简单的 FIFO 调度机制,所有作业提交到一个队列种,按照提交顺序运行。
随着 Hadoop 的发展,集群越来越大,使用用户越来越多,不同用户提交的任务往往具有不同的服务质量要求(Qos,Quality of Service),典型的有:
- 批处理作业,往往耗时很长,对完成时间没有严格要求
- 交互式作业,期望能够及时返回结果,如:Hive 查询
- 生产性作业,要求一定的资源保证,能够在一段期望时间内完成
因此其他更加灵活,更充分利用资源的调度器诞生。为了适用多用户的资源调度,目前主要有两种多用户资源调度器设计思路:第一种在物理集群上虚拟多个 Hadoop 集群,各自拥有全套独立的 Hadoop 服务,典型代表是HOD(Hadoop on Demand)调度器;另一种是扩展 Yarn 调度器,支持多个队列多个用户。主要介绍 Yarn 调度器。
Yarn 资源调度器基本架构
基本架构
Yarn 的资源调度器是插拔式的,定义了一整套接口规范(用户可以按需实现自己的调度器)。
yarn.resourcemanager.scheduler.class
参数设置使用哪种调度器,所有资源调度器都实现接口 org.apache.haddoop.yarn.server.resourcemanager.scheduler.ResourceScheduler
Yarn 资源管理器实际上是一个事件处理器,需要处理来自外部的6中 SchedulerEventType 类型的事件,并进行相应的处理
- NODE_REMOVED,集群移除了一个计算节点(故障或手动移除),需要从可分配资源中移除
- NODE_ADDED,集群新增了一个计算节点,需要将新增资源加入可分配资源中
- APPLICATION_ADDED,ResourceManager 接收到一个新的 Application
- APPLICATION_REMOVED,一个 Application 运行结束
- CONTAINER_EXPIRED,ResourceManager 分配了 Container 给 ApplicationMaster,一定时间内 ApplicationMaster 没有使用该 Container,会对资源进行回收再分配
- NODE_UPDATE,ResourceManager 接收到 NodeManager 心跳消息后,触发该事件
这些事件的触发实现会影响资源调度器的资源分配机制
资源表示模型
当前 Yarn 支持内存和CPU两种资源类型的管理和分配,采用动态资源分配机制。NodeManager 启动时向 ResourceManager 注册,包含该节点可分配的CPU和内存总量,可以通过配置项设置:
<!-- 可分配物理内存,默认:8GB -->
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>8192</value>
</property>
<!-- 单位物理内存最多可使用的虚拟内存量,默认:2.1 -->
<!-- 表示每使用1MB,最多可使用2.1MB虚拟内存 -->
<property>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>2.1</value>
</property>
<!-- 可分配的虚拟CPU个数,默认:8-->
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>4</value>
</property>
为了更细粒度的划分CPU资源和考虑到CPU的性能异构性,Yarn 允许管理员根据实际需要和CPU性能将每个物理CPU划分成若干个虚拟CPU,可以为每个节点单独配置可用的虚拟CPU个数。
资源调度模型
双层资源调度模型
Yarn 采用有双层调度策略,ResourceManager 将资源分配给 ApplicationMaster,ApplicationMaster 再将资源分配给各个任务。
Yarn 的资源分配过程是异步的,将资源分配给一个应用程序后,不会立刻推给对应的 ApplicationMaster,会先放入一个缓冲区等待 ApplicationMaster 通过心跳来主动拉取,即 pull-based 通信模型(与MRv1一样)。
- NodeManager 通过心跳向 ResourceManager 汇报节点信息
- ResourceManager 应答 NodeManager 的心跳请求,包括需要释放的 Container 列表等信息
- ResourceManager 收到 NodeManager 的请求,触发一个 NODE_UPDATE 事件
- ResourceScheduler 收到 NODE_UPDATE 事件,按照一定的策略分配该节点上的资源给各个应用程序,分配结果放到内存中
- ApplicationMaster 通过心跳向 ResourceManager 获取最新分配的 Container
- ResourceManager 应答 ApplicationMaster 的心跳请求,发送分配资源结果
- ApplicationMaster 接收到分配的 Container 列表,将其分配给内部的任务
资源保证机制
当应用程序申请的资源暂时无法保证时,一种方法是为任务预留资源,直到积累充足的资源,称为增量资源分配。另一种方式是:当资源不足以运行任务,放弃当前资源,直到出现能够一次性满足任务需求的资源出现,再分配给任务,称为一次性资源分配。
Yarn 采用增量分配机制,虽然占用资源,造成资源浪费,但是第二种方式会产生饿死现象(应用程序永远等不到满足的资源)。
资源抢占模型
资源调度器中,每个队列可以设置一个最小和最大资源量(资源紧缺时队列能够保证的资源量和极端情况下队列不能超过的资源使用量)。资源抢占发生的原因在于最小资源量的设置,最小资源量并不能保证队列空闲时依然占用资源。
通常为了提高资源利用率,调度器会将负载较轻的队列资源暂时分配给负载重的队列,当负载较轻队列收到新提交的应用程序时,才会将本该数据该队列的资源分配给他,但是由于此时这些资源可能正被其他队列使用,因此只能等待其他队列释放这些资源。为了防止不确定的等待时间过长,调度器会进行资源抢占。
假设集群资源总量为100,分为三个队列(分配最小和最大资源):QueueA(10, 15),QueueB(20, 35),QueueC(60, 65)
某一时刻他们需要的资源和使用的资源分别为:(0, 5)、(10, 30)、(60, 65),QueueA 负载较轻,部分资源暂时不会使用,将5个资源分给 QueueB(2) 和 QueueC(3),同时 QueueB 和 QueueC 除了使用 QueueA 的资源,还使用了系统共享的10个资源。
此时,QueueA 增加了新的应用程序,共需要20个资源,则调度器需要从 QueueB he QueueC 中抢占5个属于 QueueA 的资源(通常会等待一段时间才强制回收资源)。整个过程如下图:
抢占功能需要调度器实现
PreemptableResourceScheduler
接口,并且yarn.resourcemanager.scheduler.monitor.enable
设置为 true 时才会启用。
Yarn 层级队列管理
层级队列管理机制
在早期版本中,Hadoop 采用评级队列组织方式,用户和资源扁平化分配。随着 Hadoop 的应用广泛,扁平化的队列组织已经不能满足需求。出现了更复杂一些的层级队列,具有以下特点:
- 子队列
- 队列可以嵌套
- 应用程序只能提交到最底层的队列
- 最少容量
- 每个子队列都有“最少容量比”属性,表示可使用父队列容量的百分比
- 调度器总是优先选择当前资源使用率最低的队列,并分配资源
- 最大容量
- 默认情况最大容量无限大,其他队列空闲时,可以占用父队列的全部资源
同时对于队列的管理机制也随着队列的层级更加灵活。
层级队列的命名:父队列与子队列采用“.”连接:
// 队列命名
ROOT
ROOT.A
ROOT.A.A1
ROOT.A.A2
...
Capacity Scheduler
Yahoo! 开发的多用户调度器,以队列为单位划分资源,主要有以下特点:
- 计算能力保证。每个队列会配置一定计算资源(最低资源保证和资源使用上限),所有提交到队列中的作业共享该队列中的资源。
- 灵活性。队列中空闲资源会被分配给那些未达到资源使用上限的队列,在队列有新的资源需求时,分配给其他队列的资源会被归还。
- 多重租赁。综合考虑多种约束防止单个作业、用户或者队列独占队列或者集群中的资源。
- 安全保证。每个队列有严格的ACL列表访问控制。
- 动态更新配置文件。各种配置参数可以由管理员动态修改,实现在线集群管理。
当前仅支持内存资源的调度
资源分配相关参数
配置项(百分比) | 描述 | 解释 |
---|---|---|
capacity | 队列的资源容量 | 保证每个队列的容量。 所有队列容量之和应小于100。 |
maximum-capacity | 队列的资源上限 | 实际使用资源可以超过上限 |
minimun-user-limit-percent | 每个用户最低资源 | |
user-limit-factor | 每个用户最低可使用资源量 | 任何时刻都不能超过 |
限制应用程序相关参数
配置项 | 描述 | 解释 |
---|---|---|
maximum-applications | 处于等待和运行状态的程序数量上限 | 强限制项 可以对集群和队列设置 |
maximum-am-resource-percent | 用于运行AppMaster的资源上限 | 百分比设置 可以对集群和队列设置 |
访问和权限控制相关参数
配置项 | 描述 | 解释 |
---|---|---|
state | 队列状态 STOPPED/ RUNNING | STOPPED队列不可以提交应用程序 正在运行的可以正常结束 |
acl_submit_applications | 限定可以提交应用程序的用户 | 队列具有继承属性 |
acl_administer_queue | 指定队列管理员 |
当需要动态修改队列资源配置时,可修改配置文件
conf/capacity-scheduler.xml
,然后运行yarn mradmin -refreshQueues
命令。
Fair Shceduler
Facebook 开发的多用户调度器,以队列为单位划分资源,主要有以下特点:
- 资源公平共享。每个队列中,可以按照FIFO、Fair(最大最小公平算法)或DRF(公平调度)策略分配资源。默认为Fair,如果队列中有3个应用程序,各自能得到1/3的资源。
- 支持资源抢占。队列的剩余资源可以共享给其他队列,并且可以在需要的时候回收资源。采用先等待再强制回收的策略,会杀死一部分任务来释放资源。
- 负载均衡。提供了一个基于任务数目的负载均衡机制,尽可能将任务均匀的分配到各个节点。
- 提高小应用程序响应时间。采用的最大最小公平算法,允许小作业快速获取资源。
Fair Shceduler 也添加了多层级别的资源限制条件。一部分配置在 yarn-site.xml
中,主要配置调度器级别的参数;另一部分在自定义配置文件(默认是 fair-scheduler.xml
),主要配置各个队列的资源和权重。
调度器配置项
配置项 | 描述 |
---|---|
yarn.scheduler.fair.allocation.file | 自定义配置文件的位置 |
yarn.scheduler.fair.user-as-default-queue | 未指定队列名时,是否指定用户名作为提交程序的队列名 |
yarn.scheduler.fair.preemption | 启用抢占机制,默认:false |
yarn.scheduler.fair.assignmultiple | 启动批量分配大量资源,默认:false |
yarn.scheduler.fair.max.assign | 批量分配 Container 数目,默认:-1 |
队列配置项
配置项 | 描述 | 解释 |
---|---|---|
minResource | 最少资源保证 | “X mb,Y vcores” |
maxResource | 最大资源限制 | “X mb,Y vcores” |
maxRunningApps | 最多同时运行的数目 | |
minSharePreemptionTimeout | 最小共享量抢占时间 | 等待该时间后,强制释放资源 |
schedulingMode schedulingPolicy |
队列调度模式 | FIFO\Fair\DRF |
aclSubmitApps | 限定可以提交应用程序的用户 | 队列具有继承属性 |
aclAdministerApps | 指定队列管理员 |
推荐书籍
《Hadoop技术内幕:深入解析YARN架构设计与实现原理》