原文链接:深入理解LinuxCgroup系列(三):显存
通过下篇文章的学习,我们学会了怎么查看当前cgroup的信息,怎样通过操作/sys/fs/cgroup目录来动态设置cgroup,也学会了怎么设置CPUshares和CPUquota来控制slice内部以及不同slice之间的CPU使用时间。本文将把重心转移到显存上,通过具体的示例来演示怎么通过cgroup来限制显存的使用。
1.找寻迷路显存
下篇文章告诉我们,CPUcontroller提供了两种方式来限制CPU使用时间,其中CPUShares拿来设置相对权重,CPUQuota拿来限制user、service或VM的CPU使用时间比率。诸如:假如一个user同时设置了CPUShares和CPUQuota,假定CPUQuota设置成50%,这么在该user的CPU使用量达到50%之前,可以仍然根据CPUShares的设置来使用CPU。
对于显存而言linux内存使用情况,在CentOS7中,systemd早已帮我们将memory绑定到了/sys/fs/cgroup/memory。systemd只提供了一个参数MemoryLimit来对其进行控制,该参数表示某个user或service所能使用的数学显存总数。拿之前的用户tom举例linux命令手册,它的UID是1000,可以通过以下命令来设置:
$ systemctl set-property user-1000.slice MemoryLimit=200M
现今使用用户tom登陆该系统,通过stress命令形成8个子进程,每位进程分配256M显存:
$ stress --vm 8 --vm-bytes 256M
根据想像,stress进程的显存使用量早已超出了限制,此时应当会触发oom-killer,但实际上进程仍在运行红旗linux官网,这是为何呢?我们来看一下目前占用的显存:
$ cd /sys/fs/cgroup/memory/user.slice/user-1000.slice
$ cat memory.usage_in_bytes
209661952
奇怪,占用的显存还不到200M,剩下的显存都跑哪去了呢?别慌,你是否还记得linux系统中的显存使用不仅包括数学显存,还包括交换分区,也就是swap,我们来瞧瞧是不是swap搞的鬼。先停止刚才的stress进程,稍等30秒,观察一下swap空间的占用情况:
$ free -h
total used free shared buff/cache available
Mem: 3.7G 180M 3.2G 8.9M 318M 3.3G
Swap: 3.9G 512K 3.9G
重新运行stress进程:
$ stress --vm 8 --vm-bytes 256M
查看显存使用情况:
$ cat memory.usage_in_bytes
209637376
发觉显存占用正好在200M以内。再看swap空间占用情况:
$ free
total used free shared buff/cache available
Mem: 3880876 407464 3145260 9164 328152 3220164
Swap: 4063228 2031360 2031868
和刚才相比,多了2031360-512=2030848klinux内存使用情况,如今基本上可以确定当进程的使用量达到限制时,内核会尝试将数学显存中的数据联通到swap空间中,因而让显存分配成功。我们可以精确估算出tom用户使用的数学显存+交换空间总数,首先须要分别查看tom用户的数学显存和交换空间使用量:
$ egrep "swap|rss" memory.stat
rss 209637376
rss_huge 0
swap 1938804736
total_rss 209637376
total_rss_huge 0
total_swap 1938804736
可以看见化学显存使用量为209637376字节,swap空间使用量为1938804736字节,总数为(209637376+1938804736)/1024/1024=2048M。而stress进程须要的显存总数为256*8=2048M,二者相等。
这个时侯假如你每隔几秒就查看一次memory.failcnt文件,都会发觉这个文件上面的数值仍然在下降:
$ cat memory.failcnt
59390293
从前面的结果可以看出,当化学显存不够时,才会触发memory.failcnt上面的数目加1,但此时进程不一定会被杀害,内核会尽量将数学显存中的数据联通到swap空间中。
2.关掉swap
为了更好地观察cgroup对显存的控制,我们可以用户tom不使用swap空间,实现方式有以下几种:
将memory.swappiness文件的值更改为0:
$ echo 0 > /sys/fs/cgroup/memory/user.slice/user-1000.slice/memory.swappiness
这样设置完成之后,即使系统开启了交换空间,当前 cgroup 也不会使用交换空间。
2. 直接关闭系统的交换空间:
$ swapoff -a
如果想永久生效,还要注释掉 `/etc/fstab` 文件中的 swap。
假如你既不想关掉系统的交换空间,又想让tom不使用swap空间,里面给出的第一个方式是有问题的:
倘若依照常规思路去解决这个问题,可能会十分棘手,我们可以另辟蹊径,从PAM入手。
LinuxPAM(PluggableAuthenticationModules)是一个系统级用户认证框架,PAM将程序开发与认证方法进行分离,程序在运行时调用附加的“认证”模块完成自己的工作。本地系统管理员通过配置选择要使用什么认证模块,其中/etc/pam.d/目录专门用于储存PAM配置,用于为具体的应用程序设置独立的认证形式。比如,在用户通过ssh登陆时,将会加载/etc/pam.d/sshd上面的策略。
从/etc/pam.d/sshd入手,我们可以先创建一个shell脚本:
$ cat /usr/local/bin/tom-noswap.sh
#!/bin/bash
if [ $PAM_USER == 'tom' ]
then
echo 0 > /sys/fs/cgroup/memory/user.slice/user-1000.slice/memory.swappiness
fi
之后在/etc/pam.d/sshd中通过pam_exec调用该脚本,在`/etc/pam.d/sshd`的末尾添加一行,内容如下:
$ session optional pam_exec.so seteuid /usr/local/bin/tom-noswap.sh
如今再使用tom用户登入,都会发觉memory.swappiness的值弄成了0。
这儿须要注意一个前提:起码有一个用户tom的登入会话,且通过systemctlset-propertyuser-1000.sliceMemoryLimit=200M命令设置了limit,/sys/fs/cgroup/memory/user.slice/user-1000.slice目录才能存在。所以里面的所有操作,一定要保证起码保留一个用户tom的登入会话。
3.控制显存使用
关掉了swap以后,我们就可以严格控制进程的显存使用量了。还是使用开头提及的事例,使用用户tom登陆该系统,先在第一个shell窗口运行以下命令:
$ journalctl -f
打开第二个shell窗口(还是tom用户),通过stress命令形成8个子进程,每位进程分配256M显存:
$ stress --vm 8 --vm-bytes 256M
stress: info: [30150] dispatching hogs: 0 cpu, 0 io, 8 vm, 0 hdd
stress: FAIL: [30150] (415) <-- worker 30152 got signal 9
stress: WARN: [30150] (417) stress: FAIL: [30150] (415) <-- worker 30151 got signal 9
stress: WARN: [30150] (417) now reaping child worker processes
stress: FAIL: [30150] (415) <-- worker 30154 got signal 9
stress: WARN: [30150] (417) now reaping child worker processes
stress: FAIL: [30150] (415) <-- worker 30157 got signal 9
stress: WARN: [30150] (417) now reaping child worker processes
stress: FAIL: [30150] (415) <-- worker 30158 got signal 9
stress: WARN: [30150] (417) now reaping child worker processes
stress: FAIL: [30150] (451) failed run completed in 0s
如今可以看见stress进程很快被kill掉了,回到第一个shell窗口,会输出以下信息:
由此可见cgroup对显存的限制奏效了,stress进程的显存使用量超出了限制,触发了oom-killer,因而杀害进程。