上一篇文章中介绍了如何管理cgroup,从这篇开始将介绍具体的subsystem。node
本篇将介绍一个简单的subsystem,名字叫pids,功能是限制cgroup及其全部子孙cgroup里面能建立的总的task数量。shell
注意:这里的task指经过fork和clone函数建立的进程,因为clone函数也能建立线程(在Linux里面,线程是一种特殊的进程),因此这里的task也包含线程,本文统一以进程来表明task,即本文中的进程表明了进程和线程ubuntu
本篇全部例子都在ubuntu-server-x86_64 16.04下执行经过segmentfault
在ubuntu 16.04里面,systemd已经帮咱们将各个subsystem和cgroup树绑定并挂载好了,咱们直接用现成的就能够了。bash
#从这里的输出能够看到,pids已经被挂载在了/sys/fs/cgroup/pids,这是systemd作的 dev@dev:~$ mount|grep pids cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
建立子cgroup,取名为test函数
#进入目录/sys/fs/cgroup/pids/并新建一个目录,即建立了一个子cgroup dev@dev:~$ cd /sys/fs/cgroup/pids/ dev@dev:/sys/fs/cgroup/pids$ sudo mkdir test #这里将test目录的owner设置成dev帐号,这样后续操做就不用每次都敲sudo了,省去麻烦 dev@dev:/sys/fs/cgroup/pids$ sudo chown -R dev:dev ./test/
再来看看test目录下的文件ui
#除了上一篇中介绍的那些文件外,多了两个文件 dev@dev:/sys/fs/cgroup/pids$ cd test dev@dev:/sys/fs/cgroup/pids/test$ ls cgroup.clone_children cgroup.procs notify_on_release pids.current pids.max tasks
下面是这两个文件的含义:线程
pids.current: 表示当前cgroup及其全部子孙cgroup中现有的总的进程数量code
#因为这是个新建立的cgroup,因此里面尚未任何进程 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.current 0
pids.max: 当前cgroup及其全部子孙cgroup中所容许建立的总的最大进程数量,在根cgroup下没有这个文件,缘由显而易见,由于咱们没有必要限制整个系统所能建立的进程数量。server
#max表示没作任何限制 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.max max
这里咱们演示一下如何让限制功能生效
#--------------------------第一个shell窗口---------------------- #将pids.max设置为1,即当前cgroup只容许有一个进程 dev@dev:/sys/fs/cgroup/pids/test$ echo 1 > pids.max #将当前bash进程加入到该cgroup dev@dev:/sys/fs/cgroup/pids/test$ echo $$ > cgroup.procs #--------------------------第二个shell窗口---------------------- #从新打开一个bash窗口,在里面看看cgroup “test”里面的一些数据 #由于这是一个新开的bash,跟cgroup ”test“没有任何关系,因此在这里运行命令不会影响cgroup “test” dev@dev:~$ cd /sys/fs/cgroup/pids/test #设置的最大进程数是1 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.max 1 #目前test里面已经有了一个进程,说明不能在fork或者clone进程了 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.current 1 #这个进程就是第一个窗口的bash dev@dev:/sys/fs/cgroup/pids/test$ cat cgroup.procs 3083 #--------------------------第一个shell窗口---------------------- #回到第一个窗口,随便运行一个命令,因为当前pids.current已经等于pids.max了, #因此建立新进程失败,因而命令运行失败,说明限制生效 dev@dev:/sys/fs/cgroup/pids/test$ ls -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: Resource temporarily unavailable
当前cgroup中的pids.current和pids.max表明了当前cgroup及全部子孙cgroup的全部进程,因此子孙cgroup中的pids.max大小不能超过父cgroup中的大小,若是子cgroup中的pids.max设置的大于父cgroup里的大小,会怎么样?请看下面的演示
#继续使用上面的两个窗口 #--------------------------第二个shell窗口---------------------- #将pids.max设置成2 dev@dev:/sys/fs/cgroup/pids/test$ echo 2 > pids.max #在test下面建立一个子cgroup dev@dev:/sys/fs/cgroup/pids/test$ mkdir subtest dev@dev:/sys/fs/cgroup/pids/test$ cd subtest/ #将subtest的pids.max设置为5 dev@dev:/sys/fs/cgroup/pids/test/subtest$ echo 5 > pids.max #将当前bash进程加入到subtest中 dev@dev:/sys/fs/cgroup/pids/test/subtest$ echo $$ > cgroup.procs #--------------------------第三个shell窗口---------------------- #从新打开一个bash窗口,看一下test和subtest里面的数据 #test里面的数据以下: dev@dev:~$ cd /sys/fs/cgroup/pids/test dev@dev:/sys/fs/cgroup/pids/test$ cat pids.max 2 #这里为2表示目前test和subtest里面总的进程数为2 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.current 2 dev@dev:/sys/fs/cgroup/pids/test$ cat cgroup.procs 3083 #subtest里面的数据以下: dev@dev:/sys/fs/cgroup/pids/test$ cat subtest/pids.max 5 dev@dev:/sys/fs/cgroup/pids/test$ cat subtest/pids.current 1 dev@dev:/sys/fs/cgroup/pids/test$ cat subtest/cgroup.procs 3185 #--------------------------第一个shell窗口---------------------- #回到第一个窗口,随便运行一个命令,因为test里面的pids.current已经等于pids.max了, #因此建立新进程失败,因而命令运行失败,说明限制生效 dev@dev:/sys/fs/cgroup/pids/test$ ls -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: Resource temporarily unavailable #--------------------------第二个shell窗口---------------------- #回到第二个窗口,随便运行一个命令,虽然subtest里面的pids.max还大于pids.current, #但因为其父cgroup “test”里面的pids.current已经等于pids.max了, #因此建立新进程失败,因而命令运行失败,说明子cgroup中的进程数不只受本身的pids.max的限制, #还受祖先cgroup的限制 dev@dev:/sys/fs/cgroup/pids/test/subtest$ ls -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: Resource temporarily unavailable
并非全部状况下都是pids.max >= pids.current,在下面两种状况下,会出现pids.max < pids.current 的状况:
设置pids.max时,将其值设置的比pids.current小
#继续使用上面的三个窗口 #--------------------------第三个shell窗口---------------------- #将test的pids.max设置为1 dev@dev:/sys/fs/cgroup/pids/test$ echo 1 > pids.max dev@dev:/sys/fs/cgroup/pids/test$ cat pids.max 1 #这个时候就会出现pids.current > pids.max的状况 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.current 2 #--------------------------第一个shell窗口---------------------- #回到第一个shell #仍是运行失败,说明虽然pids.current > pids.max,但限制建立新进程的功能仍是会生效 dev@dev:/sys/fs/cgroup/pids/test$ ls -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: Resource temporarily unavailable
pids.max只会在当前cgroup中的进程fork、clone的时候生效,将其余进程加入到当前cgroup时,不会检测pids.max,因此将其余进程加入到当前cgroup有可能会致使pids.current > pids.max
#继续使用上面的三个窗口 #--------------------------第三个shell窗口---------------------- #将subtest中的进程移动到根cgroup下,而后删除subtest dev@dev:/sys/fs/cgroup/pids/test$ sudo sh -c 'echo 3185 > /sys/fs/cgroup/pids/cgroup.procs' #里面没有进程了,说明移动成功 dev@dev:/sys/fs/cgroup/pids/test$ cat subtest/cgroup.procs #移除成功 dev@dev:/sys/fs/cgroup/pids/test$ rmdir subtest/ #这时候test下的pids.max等于pids.current了 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.max 1 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.current 1 #--------------------------第二个shell窗口---------------------- #将当前bash加入到test中 dev@dev:/sys/fs/cgroup/pids/test/subtest$ cd .. dev@dev:/sys/fs/cgroup/pids/test$ echo $$ > cgroup.procs #--------------------------第三个shell窗口---------------------- #回到第三个窗口,查看相关信息 #第一个和第二个窗口的bash都属于test dev@dev:/sys/fs/cgroup/pids/test$ cat cgroup.procs 3083 3185 dev@dev:/sys/fs/cgroup/pids/test$ cat pids.max 1 #出现了pids.current > pids.max的状况,这是由于咱们将第二个窗口的shell加入了test dev@dev:/sys/fs/cgroup/pids/test$ cat pids.current 2 #--------------------------第二个shell窗口---------------------- #对fork调用的限制仍然生效 dev@dev:/sys/fs/cgroup/pids/test$ ls -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: retry: No child processes -bash: fork: Resource temporarily unavailable
清理
#--------------------------第三个shell窗口---------------------- dev@dev:/sys/fs/cgroup/pids/test$ sudo sh -c 'echo 3185 > /sys/fs/cgroup/pids/cgroup.procs' dev@dev:/sys/fs/cgroup/pids/test$ sudo sh -c 'echo 3083 > /sys/fs/cgroup/pids/cgroup.procs' dev@dev:/sys/fs/cgroup/pids/test$ cd .. dev@dev:/sys/fs/cgroup/pids$ sudo rmdir test/
本文介绍了如何利用pids这个subsystem来限制cgroup中的进程数,以及一些要注意的地方,总的来讲pids比较简单。下一篇将介绍稍微复杂点的内存控制。