Yarn的三种资源调度器
在Yarn框架中,调度器是一块很重要的内容。有了合适的调度规则,就可以保证多个应用可以在同一时间有条不紊的工作。最原始的调度规则就是FIFO,即按照用户提交任务的时间来决定哪个任务先执行,但是这样很可能一个大任务独占资源,其他的资源需要不断的等待。也可能一堆小任务占用资源,大任务一直无法得到适当的资源,造成饥饿。所以FIFO虽然很简单,但是并不能满足我们的需求。
一、查看用了哪种调度器
1. web查看
http://localhost:8088/cluster/scheduler
2. 命令行查看某一个队列
lcc@lcc ~$ yarn queue -status default 18/12/15 10:55:10 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/12/15 10:55:10 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable Queue Information : Queue Name : default State : RUNNING Capacity : 100.0% Current Capacity : .0% Maximum Capacity : 100.0% Default Node Label expression : Accessible Node Labels : * lcc@lcc ~$
二、调度器的选择
在Yarn中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,Fair Scheduler。
1、FIFO调度器(先进先出调度)
上图为FIFO调度器的执行过程示意图。
FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。
FIFO Scheduler是最简单也是最容易理解的调度器,也不需要任何配置,但它并不适用于共享集群。大的应用可能会占用所有集群资源,这就导致其它应用被阻塞。在共享集群中,更适合采用Capacity Scheduler或Fair Scheduler,这两个调度器都允许大任务和小任务在提交的同时获得一定的系统资源。
从执行过程图中可以看出,在FIFO 调度器中,小任务会被大任务阻塞。
2、Capacity调度器(容量预先分配调度)
上图为Capacity调度器的执行过程示意图。
Capacity调度器以队列为单位划分资源。会给每个队列配置最小保证资源和最大可用资源。最小配置资源保证队列一定能拿到这么多资源,有空闲可共享给其他队列使用;最大可用资源限制队列最多能使用的资源,防止过度消耗。
队列内部可以再嵌套,形成层级结构。队列内资源默认采用 FIFO 的方式分配。如下图所示。
优点:
- 队列最低资源保障,防止小应用饿死;
- 空闲容量共享,当队列配置资源有空闲时可共享给其他队列使用
缺点:
- 队列配置繁琐,父队列、子队列都要单独配置优先级、最大资源、最小资源、用户最大资源、用户最小资源、用户权限配置等等。工程中会写个程序,自动生成该配置;
特征
- 分层队列 (Hierarchical Queues):支持队列分层结构,子队列可分配父队列可用资源。
- 容量保证 (Capacity Guarantees):每个队列都会配置最小容量保证,当集群资源紧张时,会保证每个队列至少能分到的资源。
- 弹性 (Elasticity):当队列配置资源有空闲时,可以分配给其他有资源需求的队列。当再次需要这些资源时可以抢夺回这些资源。
- 安全性 (Security):每个队列都有严格的 ACL,用于控制哪些用户可以向哪些队列提交应用程序。
- 多租户 (Multi-tenancy):提供全面的限制以防止单个应用程序、用户和队列从整体上独占队列或集群的资源。
- 优先级调度 (Priority Scheduling):此功能允许以不同的优先级提交和调度应用程序。同时队列间也支持优先级配置(2.9.0 后支持)。
- 绝对资源配置 (Absolute Resource Configuration):管理员可以为队列指定绝对资源,而不是提供基于百分比的值(3.1.0 后支持)。
- 资源池配置:可将 NodeManager 分割到不同的资源池中,资源池中配置队列,进行资源隔离。同时资源池有共享和独立两种模式。在共享情况下,多余的资源会共享给 default 资源池。
配置
假设队列层级如下:
root
├── prod
└── dev
├── eng
└── science
可以通过配置 capacity-scheduler.xml
来实现:
<configuration> <property> <name>yarn.scheduler.capacity.root.queues</name> <value>prod,dev</value> </property> <property> <name>yarn.scheduler.capacity.root.dev.queues</name> <value>eng,science</value> </property> <property> <name>yarn.scheduler.capacity.root.prod.capacity</name> <value>40</value> </property> <property> <name>yarn.scheduler.capacity.root.dev.capacity</name> <value>60</value> </property> <property> <name>yarn.scheduler.capacity.root.dev.eng.capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.dev.science.capacity</name> <value>50</value> </property> </configuration>
除了容量配置外,还可以配置单个用户或者程序能够使用的最大资源数,同时可以运行几个应用,权限ACL控制等。
3、Fair调度器(公平分配调度)
上图为Fair调度器的执行过程示意图。
在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。如下图所示,当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
需要注意的是,在Fair调度器图中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终的效果就是Fair调度器即得到了高的资源利用率又能保证小任务及时完成。
Fair 调度器的设计目标是为所有的应用分配公平的资源(对公平的定义可以通过参数来设置)。
优点
- 分配给每个应用程序的资源取决于其优先级;
- 它可以限制特定池或队列中的并发运行任务。
特征
- 公平调度器,就是能够共享整个集群的资源
- 不用预先占用资源,每一个作业都是共享的
- 每当提交一个作业的时候,就会占用整个资源。如果再提交一个作业,那么第一个作业就会分给第二个作业一部分资源,第一个作业也就释放一部分资源。再提交其他的作业时,也同理。也就是说每一个作业进来,都有机会获取资源。
- 权重属性,并把这个属性作为公平调度的依据。如把两个队列权重设为 2 和 3,当调度器分配集群 40:60 资源给两个队列时便视作公平。
- 每个队列内部仍可以有不同的调度策略。队列的默认调度策略可以通过顶级元素 进行配置,如果没有配置,默认采用公平调度。
三、Fair Scheduler与Capacity Scheduler区别
相同点
- 都支持多用户多队列,即:适用于多用户共享集群的应用环境
- 都支持层级队列
- 支持配置动态修改,更好的保证了集群的稳定运行。
- 均支持资源共享,即某个队列中的资源有剩余时,可共享给其他缺资源的队列
- 单个队列均支持优先级和FIFO调度方式
不同点
- Capacity Scheduler的调度策略是,可以先选择资源利用率低的队列,然后在队列中通过FIFO或DRF进行调度。
- Fair Scheduler的调度策略是,可以使用公平排序算法选择队列,然后再队列中通过Fair(默认)、FIFO或DRF的方式进行调度。