在前面的文章中讲过容量调度中队列的容量配置、容量调度中的优先级调度。
实际使用场景中可能会出现这么几种情况:
对于这些场景就可以通过配置资源抢占来解决。保证队列的最低容量得到保证、或者高优先级的任务优先运行。
本文就来聊聊容量调度中的资源抢占。
【队列间的抢占】
容量调度中的资源抢占,最通用的方式就是在多个队列之间进行资源的抢占,保证每个队列的最小资源(队列的capacity配置)得以满足。
在rm的配置文件yarn-site.xml中增加如下配置,就可以开启队列间的抢占:
<property>
<name>yarn.resourcemanager.scheduler.monitor.enable</name>
<value>true</value>
</property>
配置完成后(需重启rm),就可以看到队列的抢占属性从disable变成enabled了。
接下来,我们就实际测试下抢占的效果。
测试的队列配置情况如下所示:
queue_test | spurs | default | |
---|---|---|---|
capacity | 10 | 40 | 50 |
maxCapacity | 100 | 100 | 100 |
注:集群总的资源为18GB内存,为了任务可以正确提交和分配资源,临时将队列的am资源占比调高了。
测试步骤:
测试情况如下所示:
queue_test队列中已经有3个任务,并且都成功分配资源并运行了:
新提交任务到default队列后,am已经分配资源并成功运行,但此时由于集群资源不够,导致任务无法申请到资源。
等待一段时间后,观察到新提交的任务从queue_test队列抢占到了3GB的资源,而queue_test队列中其中一个任务运行结束释放了资源。
从rm的界面提供的信息中也可以证实,确实发生了抢占。
到此,可以看到抢占生效了。此后如果继续往default队列或spurs队列提交任务,还会继续从queue_test中抢占资源。
【队列内的抢占】
除了可以配置队列间的抢占,还可以配置队列内的任务是否可以抢占。也就是说不仅可以抢占其他队列的资源,还可以抢占任务自身所在队列的资源。
队列内的抢占有两种方式:一种是按任务的优先级来,即高优先级的任务处于待分配状态后,将从低优先级任务抢占资源;另一种是按用户资源来划分,即队列内多个用户提交的任务,从占用资源最多的那个用户进行抢占,其本质上是保证每个用户的资源使用趋于平等。这里就举例介绍下按任务优先级来抢占。
和队列间的抢占类似,也需要在yarn-site.xml中增加如下配置项才能启用队列内的抢占。
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.infra-queue-preemption.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.intra-queue-preemption.preemption-order-policy</name>
<value>priority_first</value>
</property>
配置完成后(同样需重启rm),就可以看到对应属性从disable变成enabled了。
接下来仍旧是进行测试看看实际效果,测试方法和队列间的抢占基本一致,不过有如下两点不同:
测试情况如下所示:
queue_test队列中已经有3个任务,并且都成功分配了资源和运行,再次往队列提交任务,该任务的优先级比之前的都要高,任务的am已经分配的资源,但因集群资源不满足不会为任务分配资源(这里截图早了点,任务分配资源后会运行,其状态会变为RUNNING)
一段时间后,发生了队列间的抢占,优先级最低的任务其中一个container结束并释放了资源。
此后,再次向队列提交一个任务(优先级比正在运行的都要低),发现很长一段时间都没有发生抢占。这足以说明只有高优先级的任务可以抢占低优先级任务的资源,反过来却不行。
【抢占原理】
首先,只有使用的调度器实现了PreemptableResourceScheduler接口,并且启用了抢占;rm才会真正使用抢占这个功能。
而资源抢占是通过第三方策略触发的,这些策略通常被实现成一些可插拔式的组件类(实现指定SchedulingEditPolicy接口)。yarn提供了默认的实现类,当然,也可以通过参数配置进行指定。
rm会启动一个监测线程,在该线程中定期遍历这些策略,并调用具体实例的接口实现方法,决定是否进行抢占,抢占哪些container的资源。
资源抢占的整个过程可以概括为如下步骤:
这就是整个资源抢占的处理逻辑,个人认为,最核心的步骤在于资源分配的重新计算和标注哪些container的资源将要被抢占。
【其他配置项】
除了上面队列内抢占、队列间抢占提到的配置外,还有如下相关配置项:
<!-- 设置为观察模式,true表示不进行真正的抢占动作 -->
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.observe_only</name>
<value>true</value>
</property>
<!-- 资源抢占策略 -->
<property>
<name>yarn.resourcemanager.scheduler.monitor.policies</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.monitor.capacity.ProportionalCapacityPreemptionPolicy</value>
</property>
<!-- 抢占监测d额时间间隔 单位: 毫秒 -->
<property>
<name>yarn.resourcemanager.monitor.preemption.monitoring_interval</name>
<value>3000</value>
</property>
<!-- kill container之前的等待时长 单位: 毫秒 -->
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.max_wait_before_kill</name>
<value>15000</value>
</property>
<!-- 每次监测触发抢占的资源的最大值(集群资源的百分比) -->
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.total_preemption_per_round</name>
<value>0.1</value>
</property>
<!-- 队列(超额)使用资源可忽略不进行抢占的百分比 -->
<!-- 即队列当前已使用资源超过了capacity,但还未超过(1+0.1)*capacity,则对该队列进行抢占 -->
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.max_ignored_over_capacity</name>
<value>0.1</value>
</property>
此外,还可以单独对队列进行设置,例如指定某个队列不允许抢占。
<!-- 队列禁止抢占 -->
<property>
<name>yarn.scheduler.capacity.$QUEUE_PATH.disable_preemption</name>
<value>true</value>
</property>
<!-- 禁止队列内抢占 -->
<property>
<name>yarn.scheduler.capacity.$QUEUE_PATH.intra-queue-preemption.disable_preemption</name>
<value>true</value>
</property>
【其他问题整理】
【总结】
小结一下,本文讲述了容量调度中的资源抢占,包括队列间的资源抢占和队列内的资源抢占的配置使用,对抢占的原理、相关配置、使用上一些场景的FAQ也简单进行了简要说明。
好了,本文就介绍到这里,原创不易,点赞,在看,分享是最好的支持, 谢谢~