LSF实践专题(4):如何限制作业的最大内存

本文详细解释了为何需要在LSF中限制作业内存,介绍了LSF内部的两种内存限制方法,包括操作系统强制和LSF强制执行,以及如何通过Linuxcgroup进行内存限制。通过示例展示了如何配置LSF参数来确保作业内存不超过预设值,以防止内存泄漏和系统性能下降。
摘要由CSDN通过智能技术生成

目录

为什么需要限制作业的最大内存?

那么LSF内部是如何实现对作业的内存限制呢?

LSF内存限制如何配置?

基于Linux cgroup的内存限制

LSF内存限制应用举例


为什么需要限制作业的最大内存?

不少LSF用户都可能碰到这样的情况:提交到LSF的作业或程序,有时会出现内存泄漏,或者有意想不到的内存分配情况,使得其它进程因无法分配到足够的内存而出现异常。尽管有的客户也采用了bsub -R “rusage[mem=$number]”来为作业预留内存,以保证计算节点有足够的内存来启动和运行作业,但是用户往往对作业程序使用的内存预估不足,结果作业实际所耗内存远远大于预留内存,导致计算节点运行缓慢,甚至对系统造成影响,引发宕机。

站在一个普通的LSF用户角度,如果能通过LSF控制作业所能使用的内存大小,那么就算作业进程有内存泄漏也不会对系统造成影响(可以设置内存使用上限,当到达这个上限值后LSF自动将作业杀掉)。

站在一个LSF系统管理员的角度,如果能通过LSF限制作业所能使用的内存量,不管用户对自己的作业使用内存评估是否准确,即使作业使用内存大大超过了预留内存,都能将它们对系统的影响降到最低,从而保证整个系统的稳定性。

那么LSF内部是如何实现对作业的内存限制呢?

在不使用Linux cgroup的情况下(后文介绍Linux cgroup),LSF有两种强制内存限制的方法:

  1. 由操作系统强制执行每个进程的内存限制。在这种情况下,LSF将配置的内存限制传递给操作系统,由操作系统通过setrlimit()系统调用来进行内存限制。

  2. 由LSF强制执行每个作业的内存限制。LSF获取作业所有进程消耗的内存之和,以确定作业是否已达到所指定的内存限制。当作业所有进程的总内存超过内存限制时,LSF会依次发送以下信号来终止作业进程:SIGINT、SIGTERM和SIGKILL。

LSF内存限制如何配置?

LSF有关内存限制的设置,有两个参数:

  1. LSB_JOB_MEMLIMIT,该参数用来设置内存限制是由操作系统强制执行还是由LSF强制执行。当LSB_JOB_MEMLIMIT设为Y时,由LSF强制执行(作业级);当LSB_JOB_MEMLIMIT设为N或未定义时,由操作系统强制执行(进程级)。

  2. LSB_MEMLIMIT_ENFORCE,使能这个参数可以同时启用LSF强制执行(作业级)和操作系统强制执行(进程级)。

这两个参数的关系说明如下:

参数名

参数值

LSF强制执行(作业级)

操作系统强制执行(进程级)

LSB_JOB_MEMLIMIT

Y|y

Enabled

Disabled

N|n 或未定义

Disabled

Enabled

LSB_MEMLIMIT_ENFORCE

Y|y

Enabled

Enabled

基于Linux cgroup的内存限制

LSF还支持通过Linux cgroup来进行作业的内存限制。如果想通过Linux cgroup进行内存强制,需要在lsf.conf文件中配置:

  • LSB_RESOURCE_ENFORCE="memory"

  • LSF_PROCESS_TRACKING = Y

  • LSF_LINUX_CGROUP_ACCT = Y

配置上述参数后,如果作业进程占用的内存超过了限制,Linux cgroup内存子系统会自动终止该作业。

LSF内存限制应用举例

LSF可以通过在作业级别(bsub的-M选项)、队列级别(在lsb.queues里设置MEMLIMIT参数)或者应用级别(在lsb.applications里设置MEMLIMIT参数)设置内存限制。下面我们以作业级别为例进行介绍。

示例1:提交一个作业,指定内存限制为100K。

$ bsub -M 100 sleep 1h
Job <20894> is submitted to default queue <normal>.

说明:在默认情况下,LSF资源限制大小单位为KB,在lsf.conf可以配置LSF_UNIT_FOR_LIMITS参数来设置其它单位(MB、GB、TB、PB或EB)。

通过bjobs可以查看作业指定的内存限制(MEMLIMIT输出):

$ bjobs -l
Job <20894>, User <usr1>, Project <default>
     , Status <RUN>, Queue <normal>, Command <sleep 1h>, Share
                     group charged </usr1>
Mon Nov  1 18:01:41: Submitted from host <host1>, CWD </tmp>;
Mon Nov  1 18:01:41: Started 1 Task(s) on Host(s) <host2>, Allocated 1 Slot(s) on Host(s) <host2>, Execution Home </home/usr1>, Exe
                     cution CWD </tmp>;
Mon Nov  1 18:01:48: Resource usage collected.
                     MEM: 1 Mbytes;  SWAP: 1 Mbytes;  NTHREAD: 4
                     PGID: 17883;  PIDs: 17883 15945 15947
 
 
 MEMLIMIT
    100 K
 
 MEMORY USAGE:
 MAX MEM: 2 Mbytes;  AVG MEM: 2 Mbytes
 ……

由于我们目前并没有启用前述LSF参数,默认情况下LSF将通过操作系统来进行强制内存限制。操作系统会给作业进程设置最大驻留内存限制(max resident set)。通过刚才的bjobs输出,我们知道作业进程PID是17883,进而可以通过下面这条命令查看该进程的操作系统限制:

$ cat /proc/17883/limits
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            unlimited            unlimited            bytes     
Max core file size        unlimited            unlimited            bytes     
Max resident set          102400               unlimited            bytes     
Max processes             513391               513391               processes
Max open files            7777                 7777                 files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       513391               513391               signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us     

可以发现,上面输出中的Max resident set值是102400,即100 KB,与我们提交作业时bsub -M指定的值一致。

值得注意的是,操作系统内存强制通常允许进程最终运行到完成,换句话说,这种方式并不能确保作业内存不超过预设值,因此上面这个例子的作业可以正常完成。

接下来,我们通过LSF参数来设置更严格的内存限制。

示例2:在lsf.conf文件中配置LSB_JOB_MEMLIMIT = y,执行badmin hrestart all使其生效,查看生效后的配置命令如下:

$ badmin showconf sbd | grep LIMIT
LSB_JOB_MEMLIMIT = y

我们再次提交相同作业,仍然指定内存限制为100K。

$ bsub -M 100 sleep 1h
Job <20895> is submitted to default queue <normal>.

这个作业会因为内存超限而被LSF强制杀掉:作业exit,bhist有如下输出:

TERM_MEMLIMIT: job killed after reaching LSF memory usage limit

$ bhist -l 20895
Job <20895>, User <usr1>, Project <default>, Command <sleep 1h>
Mon Nov  1 18:03:16: Submitted from host <host1>, to Queue <normal>, CWD </tmp>;
Mon Nov  1 18:03:17: Dispatched 1 Task(s) on Host(s) <host2>, Allocated 1 Slot (s) on Host(s) <host2>, Effective RES_REQ <select[type ==local] order[r15s:pg] >;
Mon Nov  1 18:03:17: Starting (Pid 17720);
Mon Nov  1 18:03:17: Running with execution home </home/usr1>, Execution CWD </tmp>, Execution Pid <17720>;
Mon Nov  1 18:03:21: Exited with exit code 130. The CPU time used is 0.0 seconds;
Mon Nov  1 18:03:21: Completed <exit>; TERM_MEMLIMIT: job killed after reaching LSF memory usage limit;
 
 
 MEMLIMIT
    100 K
 
MEMORY USAGE:
MAX MEM: 2 Mbytes;  AVG MEM: 2 Mbytes

在lsf.conf中配置LSB_MEMLIMIT_ENFORCE = Y,也可以达到同样的效果,这里不再赘述。

我们再来看一个Linux cgroup的例子。

示例3:基于Linux cgroup内存子系统的内存限制。

按照前面介绍的方法配置后,可以通过如下命令查看参数:

$ badmin showconf sbd | egrep "LSB_RESOURCE_ENFORCE | LSF_PROCESS_TRACKING | LSF_LINUX_CGROUP_ACCT"
LSB_RESOURCE_ENFORCE = memory
LSF_PROCESS_TRACKING = Y
LSF_LINUX_CGROUP_ACCT = Y

我们提交一个吃内存的程序,并指定内存限制为100M:

$ bsub -M 100M ./eatmem_perhost
Job <21102> is submitted to default queue <normal>.

启用Linux cgroup后,可以在系统的/sys/fs/cgroup/memory/lsf目录树下查看每个作业的内存限制。这是我们刚提交的这个作业的cgroup目录,内存限制值会被记录到memory.limit_in_bytes文件里:

$ ls /sys/fs/cgroup/memory/lsf/lsf10/job.21103.6077.1635835590/
memory.failcnt                      memory.kmem.tcp.failcnt             memory.max_usage_in_bytes           memory.numa_stat                    memory.usage_in_bytes
memory.force_empty                  memory.kmem.tcp.limit_in_bytes      memory.memsw.failcnt                memory.oom_control                  memory.use_hierarchy
memory.kmem.failcnt                 memory.kmem.tcp.max_usage_in_bytes  memory.memsw.limit_in_bytes         memory.pressure_level               
memory.kmem.limit_in_bytes          memory.kmem.tcp.usage_in_bytes      memory.memsw.max_usage_in_bytes     memory.soft_limit_in_bytes          
memory.kmem.max_usage_in_bytes      memory.kmem.usage_in_bytes          memory.memsw.usage_in_bytes         memory.stat                         
memory.kmem.slabinfo                memory.limit_in_bytes               memory.move_charge_at_immigrate     memory.swappiness
$ cat /sys/fs/cgroup/memory/lsf/lsf10/job.21103.6077.1635835590/memory.limit_in_bytes 
104857600

可以看到,memory.limit_in_bytes记录的值是104857600,即100M。

该作业运行一段时间后,由于不断占用内存,最终达到预设的100M内存限制,自动被Linux cgroup强制杀掉,bjobs和bhist会输出相应信息:

$ bjobs -l 21103
 
Job <21103>, User <usr1>, Project <default>,
Status <EXIT>, Queue <normal>, Command <./eatmem_perhost
                      105 10 10>, Share group charged </usr1>
Tue Nov  2 14:46:30: Submitted from host <host1>, CWD </tmp>;
Tue Nov  2 14:46:30: Started 1 Task(s) on Host(s) <host2>, Allocated 1 Slot(s)on Host(s) <host2>, Execution Home </home/usr1>, Exe
                     cution CWD </tmp>;
Tue Nov  2 14:46:31: Exited with exit code 137. The CPU time used is 0.1 second
                     s.
Tue Nov  2 14:46:31: Completed <exit>; TERM_MEMLIMIT: job killed after reaching LSF memory usage limit.
 
 MEMLIMIT
 102400 K
 
 MEMORY USAGE:
 MAX MEM: 100 Mbytes;  AVG MEM: 33 Mbytes
$ bhist -l 21103
 
Job <21103>, User <usr1>, Project <default>, Command <./eatmem_perhost 105 10 10>
Tue Nov  2 14:46:30: Submitted from host <host1>, to Queue <normal>, CWD </tmp>;
Tue Nov  2 14:46:30: Dispatched 1 Task(s) on Host(s) <host2>, Allocated 1 Slot(s) on Host(s) <host2>, Effective RES_REQ <select[type ==local] order[r15s:pg] >;
Tue Nov  2 14:46:30: Starting (Pid 6071);
Tue Nov  2 14:46:30: Running with execution home </home/usr1>, Execution CWD </tmp>, Execution Pid <6071>;
Tue Nov  2 14:46:31: Exited with exit code 137. The CPU time used is 0.1 second
                     s;
Tue Nov  2 14:46:31: Completed <exit>; TERM_MEMLIMIT: job killed after reaching LSF memory usage limit;
 
 MEMLIMIT
 102400 K
 
MEMORY USAGE:
MAX MEM: 100 Mbytes;  AVG MEM: 33 Mbytes
 
Summary of time in seconds spent in various states by  Tue Nov  2 14:46:31
  PEND     PSUSP    RUN      USUSP    SSUSP    UNKWN    TOTAL
  0        0        1        0        0        0        1

上面3个示例表明,LSF可以在作业达到内存限制时杀掉作业,从而避免作业因占用内存过大而导致的OOM和宕机问题。配合之前介绍的bsub -R "rusage[mem=xxx]"、loadSched/loadStop等设置,可以实现比较好的内存控制效果。如果您对于LSF内存控制有任何问题,也欢迎给公众号留言。

欢迎关注下方微信公众号【HPC常青园】,共同交流HPC集群管理经验和最佳实践。如果您有关于HPC集群的具体需求,欢迎邮件沟通交流:hpc@ivyent.cn。

HPC常青园

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ivyent

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值