本篇文章将深入介绍 Yarn 三种调度器。Yarn 本身作为资源管理和调度服务,其中的资源调度模块更是重中之重。下面将介绍 Yarn 中实现的调度器功能,以及内部执行逻辑。
Yarn 最主要的功能就是资源管理与分配。本篇文章将对资源分配中最核心的组件调度器(Scheduler)进行介绍。
调度器最理想的目标是有资源请求时,立即满足。然而由于物理资源是有限的,就会存在资源如何分配的问题。针对不同资源需求量、不同优先级、不同资源类型等,很难找到一个完美的策略可以解决所有的应用场景。因此,Yarn提供了多种调度器和可配置的策略供我们选择。
Yarn 资源调度器均实现 ResourceScheduler 接口,是一个插拔式组件,用户可以通过配置参数来使用不同的调度器,也可以自己按照接口规范编写新的资源调度器。在 Yarn 中默认实现了三种调速器:FIFO Scheduler 、Capacity Scheduler、Fair Scheduler。
官方对三种调度器的介绍图。看个大概意思就行,随着调度器的不断更新迭代,这个图不再符合当下的情况。
最简单的一个策略,仅做测试用。
用一个队列来存储提交等待的任务,先提交的任务就先分资源,有剩余的资源就给后续排队等待的任务,没有资源了后续任务就等着之前的任务释放资源。
优点:
简单,开箱即用,不需要额外的配置。早些版本的 Yarn 用 FIFO 作为默认调度策略,后续改为 CapacityScheduler 作为默认调度策略。
缺点:
除了简单外都是缺点,无法配置你各种想要的调度策略(限制资源量、限制用户、资源抢夺等)。
Capacity Scheduler(后以 CS 简写代替)以队列为单位划分资源。会给每个队列配置最小保证资源和最大可用资源。最小配置资源保证队列一定能拿到这么多资源,有空闲可共享给其他队列使用;最大可用资源限制队列最多能使用的资源,防止过度消耗。
队列内部可以再嵌套,形成层级结构。队列内资源默认采用 FIFO 的方式分配。如下图所示。
优点:
缺点:
假设队列层级如下:
root
├── prod
└── dev
├── eng
└── science
可以通过配置 capacity-scheduler.xml
来实现:
yarn.scheduler.capacity.root.queues
prod,dev
yarn.scheduler.capacity.root.dev.queues
eng,science
yarn.scheduler.capacity.root.prod.capacity
40
yarn.scheduler.capacity.root.dev.capacity
60
yarn.scheduler.capacity.root.dev.eng.capacity
50
yarn.scheduler.capacity.root.dev.science.capacity
50
除了容量配置外,还可以配置单个用户或者程序能够使用的最大资源数,同时可以运行几个应用,权限ACL控制等,不是本篇重点,不再展开。可参考:cloudera - Capacity Scheduler、Hadoop doc - Capacity Scheduler、Hadoop: Capacity Scheduler yarn容量调度配置。
这里仅关注 CS 资源分配的过程。
CS 分配的是各 NM 节点上的空闲资源,NM 资源汇报请到之前的文章《4-3 RM 管理 NodeManager》中了解。
AM 通过心跳汇报资源请求,包含的信息如下。
message ResourceRequestProto {
optional PriorityProto priority = 1; // 优先级
optional string resource_name = 2; // 期望资源所在节点或机架
optional ResourceProto capability = 3; // 资源量
optional int32 num_containers = 4; // Container 数目
optional bool relax_locality = 5 [default = true]; // 是否松弛本地性
optional string node_label_expression = 6; // 所在资源池
}
NM 发送心跳给 RM 后,RM 会发送 NODE_UPDATE
事件,这个事件会由 CapacityScheduler
进行处理。
case NODE_UPDATE:
{
NodeUpdateSchedulerEvent nodeUpdatedEvent = (NodeUpdateSchedulerEvent)event;
RMNode node = nodeUpdatedEvent.getRMNode();
setLastNodeUpdateTime(Time.now());
nodeUpdate(node);
if (!scheduleAsynchronously) {
// 重点
allocateContainersToNode(getNode(node.getNodeID()));
}
}
重点在 allocateContainersToNode()
,内部逻辑如下:
这里有个预留的概念(之后会有文章专门介绍 reserve 机制):
同 Capacity Seheduler 类似,Fair Scheduler 也是一个多用户调度器,它同样添加了多层级别的资源限制条件以更好地让多用户共享一个 Hadoop 集群,比如队列资源限制、用户应用程序数目限制等。
在 Fair 调度器中,我们不需要预先占用一定的系统资源,Fair 调度器会为所有运行的 job 动态的调整系统资源。如下图所示,当第一个大 job 提交时,只有这一个 job 在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair 调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
Fair 调度器的设计目标是为所有的应用分配公平的资源(对公平的定义可以通过参数来设置)。
优点:
在 FairScheduler 中是通过在 fair-scheduler.xml
中配置队列权重,来实现「公平」的。
计算时是看(当前队列权重 / 总权重)得到当前队列能分得资源的百分比。
更详细参数配置,可参考:Yarn 调度器Scheduler详解
512mb, 4vcores
30720nb, 30vcores
100
fair
2.0
512mb, 4vcores
30720nb, 30vcores
100
fair
1.0
相同点
不同点
本篇介绍了 Yarn 中组重要的资源调度模块 ResourceScheduler,作为一个可插拔组件,默认有三种实现方式 Fifo、CapacityScheduler、FairScheduler。
文中对三个调度器的功能、特征、配置、实现进行了较为详细的分析。各位同学若对其中实现细节有兴趣可深入源码,进一步探究。