董西城《深入解析YARN》- 第6章 资源调度器
6.3 YARN资源调度器的基本架构
资源调度器的基本架构.png6.3.2 资源表示模型
NodeManager启动时会向ResourceManager注册,注册信息中包含该节点可分配的CPU和内存总量,这两个值均可通过配置选项设置,具体如下:
- ❑yarn.nodemanager.resource.memory-mb。可分配的物理内存总量,默认是8MB×1024,即8GB。
- ❑yarn.nodemanager.vmem-pmem-ratio。任务使用单位物理内存量对应最多可使用的虚拟内存量,默认值是2.1,表示每使用1MB的物理内存,最多可以使用2.1MB的虚拟内存总量。
- ❑yarn.nodemanager.resource.cpu-vcores。可分配的虚拟CPU个数,默认是8。为了更细粒度地划分CPU资源和考虑到CPU性能异构性,YARN允许管理员根据实际需要和CPU性能将每个物理CPU划分成若干个虚拟CPU,而管理员可为每个节点单独配置可用的虚拟CPU个数,且用户提交应用程序时,也可指定每个任务需要的虚拟CPU个数。比如node1节点上有8个CPU,node2上有16个CPU,且node1CPU性能是node2的2倍,那么可为这两个节点配置相同数目的虚拟CPU个数,比如均为32。由于用户设置虚拟CPU个数必须是整数,每个任务至少使用node2的半个CPU(不能更少了)。
(2)不支持的调度语义当前不支持的调度语义包括:
❑请求任意节点上的特定资源量。比如,请求任意节点上5个这样的Container:虚拟CPU个数为3,内存量为1GB。
❑请求任意机架上的特定资源量。
❑请求一组或几组符合某种特质的资源。比如,请求来自两个机架上的4个Container,其中,一个机架上2个这样的Container:虚拟CPU个数为2,内存量为2GB;
❑超细粒度资源。比如CPU性能要求、绑定CPU等。
❑动态调整Container资源,应允许根据需要动态调整Container资源量(对于长作业尤其有用)。
6.3.3 资源调度模型
(1)双层资源调度模型YARN采用了双层资源调度模型:
在第一层中,ResourceManager中的资源调度器将资源分配给各个ApplicationMaster;
在第二层中,ApplicationMaster再进一步将资源分配给它内部的各个任务。本章所介绍的资源调度器主要关注的是第一层的调度问题,至于第二层的调度策略,完全由用户应用程序自己决定
步骤1 NodeManager通过周期性心跳汇报节点信息。
步骤2 ResourceManager为NodeManager返回一个心跳应答,包括需释放的Container列表等信息。
步骤3 ResourceManager收到来自NodeManager的信息后,会触发一个NODE_UPDATE事件。
步骤4 ResourceScheduler收到NODE_UPDATE事件后,会按照一定的策略将该节点上的资源(步骤2中有释放的资源)分配各应用程序,并将分配结果放到一个内存数据结构中。
步骤5 应用程序的ApplicationMaster向ResourceManager发送周期性的心跳,以领取最新分配的Container。
步骤6 ResourceManager收到来自ApplicationMaster心跳信息后,为它分配的container将以心跳应答的形式返回给ApplicationMaster。
步骤7 ApplicationMaster收到新分配的container列表后,会将这些Container进一步分配给它内部的各个任务
image.png
资源调度器关注的是步骤4中采用的策略,即如何将节点上空闲的资源分配给各个应用程序,至于步骤7中的策略,则完全由用户应用程序自己决定
(2)资源保证机制
YARN采用了增量资源分配机制,尽管这种机制会造成浪费,但不会出现饿死现象
(3)资源分配算法
YARN资源调度器采用了主资源公平调度算法(Dominant ResourceFairness,DRF)[插图],该算法扩展了最大最小公平(max-min fairness)算法[插图],使其能够支持多维资源的调度。由于DRF被证明非常适合应用于多资源和复杂需求的环境中,因此被越来越多的系统采用,包括Apache Mesos。
在DRF算法中,将所需份额(资源比例)最大的资源称为主资源,而DRF的基本设计思想则是将最大最小公平算法应用于主资源上,进而将多维资源调度问题转化为单资源调度问题,即DRF总是最大化所有主资源中最小的,其算法伪代码如下
6.3.4 资源抢占模型
下面我们举例说明。如图6-5所示,整个集群资源总量为100(为了简便,没有区分CPU或者内存),且被分为三个队列,分别是QueueA、QueueB和QueueC。它们的最小资源量和最大资源量(由管理员配置)分别是(10,15)、(20,35)和(60,65)。某一时刻,它们尚需的资源量和正在使用的资源量分别是(0,5)、(10,30)和(60,65),即队列QueueA负载较轻,部分资源暂时不会使用,它将不会使用的5个资源共享给了其他两个队列(QueueB和QueueC分别得到2个和3个),而队列QueueB和QueueC除了使用来自队列QueueA的资源外,还使用了整个系统共享的10个资源(100–10–20–60=10)。某一时刻,队列QueueA突然增加了一批应用程序,此时共需要20个资源,则资源调度器需要从QueueB和QueueC中抢占5个本该属于QueueA的资源。需要注意的是,为了避免资源浪费,资源调度器通常会等待一段时间后才会强制回收资源,而在这段等待时间内,QueueB和QueueC可能已经释放了本该属于QueueA的资源
image.png在YARN中,资源抢占整个过程可概括为如下步骤:
-
步骤1 SchedulingEditPolicy探测到需要抢占的资源,将需要抢占的资源通过事件DROP_RESERVATION和PREEMPT_CONTAINER发送给ResourceManager。
-
步骤2 ResourceManager调用ResourceScheduler的dropContainerReservation和preempt-Container函数,标注待抢占的Container。
-
步骤3 ResourceManager收到来自ApplicationMaster的心跳信息,并通过心跳应答将待释放的资源总量和待抢占Container列表发返回给它。ApplicationMaster收到该列表后,可选择如下操作:
1)杀死这些Container。
2)选择并杀死其他Container以凑够总量。
3)不做任务处理,过段时间可能有Container自行释放资源或者由ResourceManager杀死Container -
步骤4 SchedulingEditPolicy探测到一段时间内,ApplicationMaster未自行杀死约定的Container,则将这些Container封装到KILL_CONTAINER事件中发送给ResourceManager。
-
步骤5 ResourceManager调用ResourceScheduler的killContainer函数,而Resource-Scheduler则标注这些待杀死的Container。
-
步骤6 ResourceManager收到来自NodeManager的心跳信息,并通过心跳应答将待杀死的Container列表返回给它,NodeManager收到该列表后,将这些Container杀死,并通过心跳告知ResourceManager。
-
步骤7 ResourceManager收到来自ApplicationMaster的心跳信息,并通过心跳应答将已经杀死的Container列表发送给它(可能ApplicationMaster早已通过内部通信机制知道了这些被杀死的Container)。
如何决定是否抢占某个队列的资源?在YARN中,队列是按照树形结构组织的,一个队列当前实际可以使用的资源量R取决于最小资源量A(由管理员配置)、队列资源需求量B(处于等待或者运行状态的应用程序尚需的资源总量)和同父兄弟队列的空闲资源量C(多余资源可共享给其他队列),这意味着R在不同时间点的取值是不同的,可以按照递归算法求出R=F(A,B,C),这样,如果一个队列当前正在使用资源量U>R,则需从该队列中抢占(U–R)资源。
6.4 YARN层级队列管理机制
6.4.1 层级队列管理机制
该队列组织方式具有以下特点:
❑子队列。具体包括如下两点:
❍队列可以嵌套,每个队列均可以包含子队列。
❍用户只能将应用程序提交到最底层的队列,即叶子队列。
❑最少容量。具体包括如下四点:
❍每个子队列均有一个“最少容量比”属性,表示可以使用父队列的容量的百分比。 ❍调度器总是优先选择当前资源使用率最低的队列,并为之分配资源。比如同级的两个队列Q1和Q2,它们的最少容量均为30,而Q1已使用10,Q2已使用12,则调度器会优先将资源分配给Q1。
❍最少容量不是“总会保证的最低容量”,也就是说,如果一个队列的最少容量为20,而该队列中所有队列仅使用了5,那么剩下的15可能会分配给其他需要的队列。
❍最少容量的值为不小于0的数,但也不能大于“最大容量”。
❑最大容量。具体包括如下两点:
❍为了防止一个队列超量使用资源,可以为队列设置一个最大容量,这是一个资源使用上限,任何时刻使用的资源总量都不能超过该值;
❍默认情况下队列的最大容量是无限大,这意味着,当一个队列只分配了20%的资源,所有其他队列没有应用程序时,该队列可能使用100%的资源,当其他队列有应用程序提交时,再逐步归还。
6.4.2 队列命名规则
为了防止队列名称冲突和便于识别队列,YARN采用了自顶向下的路径命名队列,其中,父队列与子队列名称采用“.”拼接。下图 是一个公司内部的组织架构,映射到YARN中,所有队列命名如下:
图6-8.png
图6-8中有两个同名的队列C,通过引入队列路径后,可以很容易区分出这两个队列,一个是"ROOT.C",另外一个是"ROOT.C.C"