本文为译文,原文链接https://issues.apache.org/jira/browse/YARN-1963
1.1 前言
在许多应用场景中,我们希望YARN的作业能够按照优先级的先后顺序来执行。在现有的机制下,为了满足这个需求,只能在使用CapacityScheduler时通过创建不同资源量的队列,(优先级越高的队列,资源量越大),然后將作业相应地按照优先级提交到这些队列上来运行。 然而,更加理想的方式是让作业支持优先级属性,并能在提交作业时指定它。YARN-1963就是来完成这一功能的,本文是这个issue的设计文档。
1.2 问题阐述
利用YARN的Capacity Scheduler调度器的已有特性,为了支持队列内作业优先级调度,可以做如下操作:
a. 创建多个队列,并根据优先级高低设置这些队列的资源量。
b. 用户根据自己所定义的优先级將作业提交到不同的队列上。
c. 可以根据需要,为每个队列设置不同的访问控制权限。
这是一种非常不灵活的方式。如果在提交作业的时候就能指定作业优先级,则会大大简化操作流程。不同优先级的作业可以运行在同一个队列里,并且可以根据优先级来共享该队列的资源。
1.3 需求阐述
a. 用户可以为他的每个作业设定一个优先级,这个优先级会在作业提交到叶子节点时用到,并由此调度作业。
b. 其他叶子队列的调度属性如user-limits(用户可提交的作业数),作业提交时间(FIFO)可以与作业优先级合理搭配:
× 一个用户如果所提交的作业数达到上限,则即使他提交的作业优先级很高,这个作业依然需要在队列中排队等待执行。
× 如果两个作业的优先级相同,则按照作业的提交时间先后顺序来执行。
c. 优先级的ACL--优先级的访问控制列表,用来限制用户无节制地提交高优先级作业的行为。
1.4 设计要点
YARN-1963 定义了作业优先级属性,并且能够根据优先级来调度作业。
这个功能主要涉及三个部分:
a. 指定作业优先级:可以通过作业提交的API 方法来指定作业优先级
b. 跟据作业优先级来调度作业:在遵循作业优先级的情况下,高优先级的作业会优先被Resource Manager调度。只有高优先级作业的需求被满足后,低优先级的作业才会被调度。
c. 访问控制列表:用户必须被授权可以提交哪些优先级的作业,这可以看成哪些用户具有特定优先级的访问权限问题。
1.5 设计细节
1.5.1 用户如何在提交作业时指定作业优先级?
a. 使用API:以下的API可以用来设定作业优先级
application.setApplicationPriority(Priority priority)
b. 使用命令行:在提交作业时,如果是mapreduce作业,可以使用如下参数设定作业优先级:
mapreduce.job.priority
1.5.2 管理员如何设定优先级?
1. 可以设定一个集群的作业优先级
管理员可以设置一个集群所能提交的最大作业优先级。所以每个作业都有一个集群作业最大优先级属性。管理员也可以 设置一个队列的队列作业默认优先级。例如
yarn.cluster.max-application-priority = 10
每个用户都可以用这个参数设定一个作业的集群作业最大优先级属性。
2. 可以设定队列作业默认优先级
管理员可以设置一个队列上默认的作业优先级。当一个作业在提交到某个队列时,如果没有指定作业优先级,则使用队列作业默认优先级。设定方法如下:
yarn.scheduler.root.<queue_name>.default-application-priority=3
注意: 队列作业优先级在capacityScheduler和FairScheduler中的设置方式是不同的。以上是capacityScheduler设置方式。
1.5.3 如何支持通过API 或者CLI 方式来设定作业的优先级属性
1. 可以通过如下方式来设定作业优先级:
管理员和用户可以通过一系列API(包括REST)来设定优先级:
a. 使用API来get/set一个队列的队列默认作业优先级
b. 使用API来get/set集群最大作业优先级
c. 使用API 来get/set一个运行中作业的优先级
CLI 同样要支持上文提到的功能。
2. 在作业运行过程中改变作业优先级
a. 普通用户可以使用某种API 来改变他所提交的正在运行的作业的优先级
b. 管理员有权可以改变任意作业的优先级
注意:
a. 用户包括管理员,必须拥有相应的ACL 权限才可以改变一个作业的优先级
b. 一旦一个作业的优先级被改变了,所有等待RM的请求的优先级都会被刷新一次
1.5.4 调度器端为支持作业优先级需要做的调整
调度器端所需要做的调整要根据调度器类别fairscheduler和capacityScheduler分为两种情况。一个简要的设计如下所述:
每个队列都可能运行很多作业,这些作业具有不同的优先级,调度器应该按照优先级先后来调度这些作业。
a. 通过修改capacity和fair调度器中的application-comparator 和 Ordering Policy方法,可以实现优先调度优先级高的作业。
b. 在处理APP_ATTEMPT_ADDED事件过程中,不管是capacity还是fair调度器,作业的优先级字段都可以从ApplicationSubmissionContext中获得,并存储到调度器端供之后的流程中使用。
1.5.5 作业优先级的访问控制列表
用户必须有相应的权限来提交某中优先级的作业。这可以避免所有用户都可以任意指定max-cluster-priority的作业,从而导致作业优先级失去意义。
a. 每个队列都有一个关于作业优先级的访问控制列表
b. capacity调度器和fair调度器因为代码不同,需要不同的访问控制列表配置。
1. 如何对队列配置作业优先级的访问控制列表
下面介绍一个在capacity调度器里设置队列作业优先级的例子:
yarn.scheduler.capacity.root.<queue_name>.<priority>.acl=user1,user2
在这个配置中,只有user1,user2可以运行指定优先级的作业。
注意: 在fairscheduler中也有类似的用于设置队列作业优先级的配置。
2. 队列作业提交的ACL和队列作业优先级ACL 之间的关系
队列作业提交的ACL是控制哪些用户有权限向该队列提交作业。而队列作业优先级ACL控制的是哪些用户在该队列上具有提交指定作业优先级的权限。队列作业优先级的ACL中的用户应该是队列作业提交ACL中的用户的一个子集。一个用户必须出现在这两个ACL 中才能提交作业到这个队列上。
注意: 如果一个用户没有出现在队列作业优先级ACL中(已经在队列作业提交ACL 中),则该用户提交的作业可以标记为Rejected。 或者另一种处理方式是使用默认的队列作业优先级来把这个作业提交到该队列上。具体采用哪种方式需要和contributos沟通确定。
1.5.6 从RM Web UI上展现作业优先级
可以从RM Web UI上查看作业详细信息,如作业优先级.
下面有几个需要注意的地方:
1. MAPREDUCE-314饿死问题
2. 抢占:如果没有抢占,则当一个低优先级作业使用了队列的全部资源时,同队列上的高优先级作业必须等待低优先级作业释放资源.这种等待时间取决于低优先级作业的运行快慢程度.一旦低优先级作业上有container运行完毕并释放相应的资源,该资源不会在此时间断内(高优先级作业完成之前)再分配给低优先级作业,而是分配给高优先级作业.基于作业优先级的抢占机制可以保证高优先级作业在指定时间内启动,而不用等待一个不确定的时间.