目录
当多个用户同时重复使用LSF集群,并对集群内的计算资源产生竞争时,LSF提供了多种不同的调度策略来对资源进行分配。
之前我们介绍过基于用户的fairshare,还有默认情况下的先来先服务(FCFS,也就是谁更早提交作业谁就优先得到资源)。
对于某些应用场景,可能有某些用户或者部门所做的工作具有更高的重要度和优先级。那么有没有办法让这些高优先级的作业优先得到计算资源呢?答案是有的。
配置不同的队列优先级
首先,我们可以请管理员设置一些比普通队列具有更高优先级的队列,并且让相关用户把高优先级的作业提交到这些高优先级的队列中。通过在lsb.queues文件里为队列配置参数PRIORITY来指定队列的优先级,数值越高,优先级也就越高。
在计算资源有限的情况下,q1和q2都有等待调度的作业,那么q1里面的作业会优先被调度,因为q1的priority更高。
如下图所示,当前集群内的32个slots已经使用了30个,还有2个空余,q1的优先级是30,q2的优先级是10。
1、为了保证公平,我们把当前的节点close,让他不能接收新的作业。
上图中bhosts -w命令显示host的状态为closed_Adm,表示当前的节点已被管理员关闭,暂时不能接受新的作业。
一般管理员需要对某些节点进行系统调整之类的操作,可以用这个操作来让节点停止接受新作业。
这样当这些节点上正在运行的作业结束后,管理员就可以对节点进行系统维护或者重启系统等操作,而不必担心这些操作导致正在运行的作业失败。
2、接下来我们向q1和q2各提交4个作业。
3、我们用badmin hopen命令将当前节点恢复到可以接受作业的状态。
我们看到,当节点被打开后,立刻有2个q1里面的作业<311>、<312>开始运行,虽然q2中的作业是更早提交的。
这时,当前节点的所有slots都已经被作业占用,所以bhosts中显示当前节点的状态为closed_Full,这个状态同样是表示节点不能再接受新的作业,但是不同于closed_Adm,这次的原因是节点的slots已经被作业填满了,所以用closed_Full来表示。
4、接下来我们用bkill将q1上两个正在运行的作业<311>、<312>强行结束。
我们看到,q1中剩余的两个作业<313>、<314>会得到新释放的两个slots并开始运行。
说明只有当高优先级队列中的作业都已经运行或者结束时,低优先级队列中的作业才有可能得到资源。
5、我们继续用bkill终止一个q1中正在运行的作业<313>。
我们看到,当q1中不再有pending状态的作业,并且又有一个空余的slots被释放出来以后,q2中排在最前面的作业<307>终于可以运行了。
对高优先级队列进行权限限制
从上面的例子我们可以看到,优先级高的队列相对于优先级低的队列,在资源分配上拥有绝对的优先权。因此,管理员需要仔细设置高优先级队列的权限,指定用户或者用户组向这个队列提交作业。
通过以前我们介绍过的USERS参数可以实现这种权限限制。
只有队列USERS参数指定的用户或者用户组才可以向这个队列提交作业,如果不配置USERS参数,默认情况是USERS=all,即所有用户都可以向当前队列提交作业。
队列间的抢占策略(preemption)
上面的例子讲的是:高优先级和低优先级的作业,同时pending的时候,如何竞争资源。
在实际使用中,如果低优先级的队列事先提交了很多作业,slots已经被占用完,高优先级队列这时才提交作业,这种情况下,一旦有任何slots资源被释放出来,或者新的计算节点开始接受作业,那么高优先级队列就立刻可以先一步得到资源。
但是,如果低优先级的作业在短时间内不会结束,那么高优先级的作业仍然没办法很快得到资源并开始运行。对于这种情况,LSF提供了一种专门的调度策略——抢占(preemption)。
抢占是指LSF自动将低优先级作业暂停(suspend),将空余出来的资源交给高优先级队列中的作业使用,等到高优先级队列的作业结束后,再将被暂停的作业恢复(resume)并继续运行。
管理员可以在队列中通过配置参数PREEMPTION来设置。
在LSF暂停作业时,会向作业发送一个SIGTSTP信号,并且将作业状态变成SSUSP(system suspend),表示被系统暂停,这时,最好是作业的应用能够捕获和处理SIGTSTP信号,否则,即使在LSF中,作业会被认为暂停了,并且释放了slots资源,但是在实际OS中,作业进程仍然在继续,并且不会释放CPU等计算资源。
如何开启抢占功能
开启抢占功能有两种主要方式:
一种是在高优先级的队列中配置:PREEMPTION = PREEMPTIVE 。
这样配置后,所有优先级比这个队列低的队列中的作业都可以被当前队列抢占。
另一种是在低优先级队列中配置:PREEMPTION = PREEMPTABLE。
这样配置后,该队列的作业可以被任何优先级高于当前队列的作业抢占。
这两种模式都可以再缩小作用范围:可以指定一个队列清单,只有在这个队列清单里的队列可以被抢占或者触发抢占。
PREEMPTION = PREEMPTIVE[q2 q3]:表示当前队列可以抢占队列q2和q3里的作业,前提是当前队列的priority高于q2和q3。
PREEMPTION = PREEMPTABLE[q1 q4]:表示当前队列的作业可以被队列q1和q4抢占,前提是当前队列的priority低于q1和q4。
1、我们将配置改成如下:
通过命令bqueues -l,我们可以看到PREEMPTION设置成功。
这时LSF集群里已经没有空余的slots,并且q2中有一个作业<307>正在运行。
2、此时向队列q1提交一个作业<415>:
当作业<415>提交到队列q1后,队列q2中正在运行的作业<307>变成SSUSP,并且<415>开始运行。
我们通过命令bhist -l 307,看到这个作业是被高优先级作业抢占了。
当作业<415>结束之后,作业<307>会重新变成RUN继续运行。
再次通过命令bhist -l观察作业<307>,我们可以看到作业重新回到Running状态。
3、这次我们提交一个-n2的作业到q1,这个作业需要两个slots才能运行。
这一次,因为队列q2中所有的作业占用的slots总数为1,而其余的slots被队列normal和q1本身的作业占用,无法抢占。在这个情况下,即使触发抢占,将队列q2的作业暂停,新的作业<416>也并不能运行,因此抢占行为就不会被触发。
如果此时队列q2中有两个或更多作业在运行,LSF会将其中两个作业暂停,并将释放出来的slots分配给q1中的作业<416>使用。
slots以外计算资源的抢占
上面的例子都是对于slots的抢占,但有的时候,作业不能运行并不是因为slots不够,而是由于节点上其它资源不够,比如内存(memory)不够。
比如当前状态下,还剩余2个slots,当前节点的内存共有6.6G。
1、我们向队列q2提交一个需要1个slot和6GB内存的作业<417>,并使其运行。
通过bhosts -l命令我们看到当前节点所剩的内存只剩下了694MB。
2、这时我们再向队列q1提交一个需要3GB的作业<418>。
虽然剩余的slots是足够的,但是当前节点的内存并不满足q1上作业的需要,因此作业<418>不能运行。
通过命令bjobs -p查看作业的pending reason:
对于这种情况,我们可以把抢占策略应用到slots以外的其它资源上。
3、打开$LSF_ENVDIR/lsbatch/{cluster_name}/configdir/lsb.params文件,配置参数PREEMPTABLE_RESOURCES :
这里可以配置一个或多个resource名字,多个resource之间用空格分开,LSF内建或者自定义的resource都可以被定义在这里,只要是数值类型的并且是被消耗型的resource就可以。
内建或者自定义的resource,在 $LSF_ENVDIR/lsf.shared文件中的resource部分,可以看到这样的定义列:RESOURCENAME TYPE INTERVAL INCREASING DESCRIPTION
只要TYPE一列为Numeric,且INCREASING一列为N的resource都可以在前面介绍的PREEMPTABLE_RESOURCES参数中使用。
4、配置好并通过命令badmin mbdrestart重启mbatchd服务
通过命令bparams -a检查参数是否设置成功:
这时,我们可以看到队列q2上的作业<417>已经被成功抢占,并且队列q1的作业<418>已经运行起来。
通过bhist -l查看被抢占的作业<417>和触发抢占的作业<418>:
总结
以上就是队列优先级以及抢占的初步应用。对于抢占策略,LSF还设定了很多进一步的规则来平衡高优先级和低优先级队列的使用情况,用来解决在一些更复杂的环境中,抢占策略可能带来的弊端。有机会我们可以在后面继续探讨。
欢迎关注下方微信公众号【HPC常青园】,共同交流HPC集群管理经验和最佳实践。如果您有关于HPC集群的具体需求,欢迎邮件沟通交流:hpc@ivyent.cn。