上一篇文章中介紹瞭如何管理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比較簡單。下一篇將介紹稍微複雜點的內存控制。