Linux系統中cgroup功能介紹

1  Cgroups簡介
1.1 What are cgroups ?
Cgroups(控制組)是Linux內核的一個功能,用來限制、統計和分離一個進程組的資源(CPU、內存、磁盤輸入輸出等)。換句話說就是,若是一個進程加入了某一個控制組,該控制組對Linux的系統資源都有嚴格的限制,進程在使用這些資源時,不能超過其最大的限制數,例如:memory資源,若是加入控制組的進程使用的memory大於其限制,可能會出現OOM錯誤(關於OOM錯誤可參看Linux內核OOM機制分析)。cgroup自己提供將進程進行分組化管理的功能和接口的基礎結構
控制組提供一種機制,將一組任務和它們的子任務聚合或劃分到有特定功能的層級結構(hierarchical)中。在Cgroups中涉及下面的幾個概念:
(1)任務(task):在 cgroups 中,任務就是系統的一個進程。
(2)控制族羣(control group):控制族羣就是一組按照某種資源限制劃分的進程。Cgroups 中的資源控制都是以控制族羣爲單位實現。一個進程能夠加入到多個控制族羣。假設這裏有個進程A,咱們要限制其使用的系統內存總量的10%,咱們就能夠建立一個memory佔用10%的cgroups。而後,將進程A添加到cgroups,那麼進程A最多佔用內存總量的10%,固然,一個cgroups通常狀況下不止一個進程。
(3)層級(hierarchy):控制族羣能夠組織成 hierarchical 的形式,既一顆控制族羣樹。子控制組自動繼承父節點的特定屬性,固然子控制組還能夠有本身特定的屬性。下面是Linux內核關於Cgroups的一種圖示:能夠看出他的層級表示:
.CPU :          "Top cpuset"
                       /       \
               CPUSet1         CPUSet2
                  |               |
               (Professors)    (Students)
 
               In addition (system tasks) are attached to topcpuset (so
               that they can run anywhere) with a limit of 20%
 
       Memory : Professors (50%), Students (30%), system (20%)
 
       Disk : Professors (50%), Students (30%), system (20%)
 
       Network : WWW browsing (20%), Network File System (60%), others (20%)
                               / \
               Professors (15%)  students (5%)
 
Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd goes
into the NFS network class.(參考Linux內核的cgroups說明
(4)Subsystem:子系統是任務組中的一個模塊,例如前面的memory就是一個子系統,該子系統是一個內存控制器。在cgroups的框架下,爲cgroups提供多種資源限制。(each subsystem has system-specific state attached to each cgroup in the hierarchy.  Each hierarchy has an instance of the cgroup virtual filesystem associated with it)。
1.2  Cgroups子系統介紹
(1)blkio --爲塊設備設定輸入/輸出限制,好比物理設備(磁盤,固態硬盤,USB 等)。
(2)cpu -- 使用調度程序提供對<span "="">CPU的cgroup任務訪問。
(3)cpuacct --自動生成cgroup中任務所使用的CPU資源報告。
(4)cpuset --爲cgroup中的任務分配獨立CPU(在多核系統)和內存節點。
(5)devices --可容許或者拒絕中的任務對設備的訪問。
(6)freezer --掛起或者恢復cgroup中的任務。
(7)memory --設定 cgroup 中任務使用的內存限制,並自動生成任務使用的內存資源報告。
(8)net_cls--使用等級識別符(classid)標記網絡數據包,可容許 Linux  流量控制程序(tc)識別從具體 cgroup 中生成的數據包。
(9)net_prio--容許管理員動態的經過各類應用程序設置網絡傳輸的優先級,相似於socket 選項的SO_PRIORITY,但它有它自身的優點。
(10)HugeTLB--HugeTLB頁的資源控制功能
         上面的幾種子系統特性能夠參考Linux的文檔cgoups子特性文檔
1.3  Cgroups在Linux中的使用和安裝
Cgroups是從Linux內核版本2.6.24開始添加進去的,Cgroups最初是由Google的工程師在2006年開發的,起初的名字叫「process containers」,在2007年更名爲「Control Groups」。首先,肯定使用的Linux發行版本是否支持該特性,我這裏使用的Linux發行版本是ubuntu,可使用下面的方式查看Ubuntu的版本。
root@ubuntu:~# lsb_release -a
No LSB modules are available.
Distributor ID:           Ubuntu
Description:               Ubuntu Trusty Tahr (development branch)
Release:   14.04
Codename:                trusty
                   使用下面的命令能夠查看Ubuntu使用的Linux內核版本。
root@ubuntu:~# uname -r
3.13.0-12-generic
                   在個人Ubuntu系統中執行lssubsys –all查看系統中默認掛載的子系統。檢查Linux內核是否支持,可使用下面的命令:
grep CGROUP /boot/config-`uname -r`
cgroup-bin_0.38-1ubuntu2_i386版本中的etc目錄下已經沒有了cgconfig.conf文件,可是咱們能夠本身建立該配置文件,這樣但cggroup啓動時,就會讀取該配置文件。這個配置文件包括mount , group and default 三個段,這三個段的順序是任意的,而且都是可選參數,該文件中用#表示的註釋。
mount section has this form:
 
              mount {
                     <controller> = <path>;
                     ...
              }
Controller:
                   表示內核支持的子系統的名字。經過/proc/cgroups文件查看系統中支持子系統。
Path:
子系統的掛載點。
                   若是沒有mount段,則controllers不會被掛載。
group section has this form:
 
              group <name> {
                     [permissions]
                     <controller> {
                            <param name> = <param value>;
                            ...
                     }
                     ...
              }
Name:
control group的名字,只能包括目錄名字容許的字符。
permissions:
可選項,指定cgroup對應的掛載點文件系統的權限
Controller:
                   內核中支持的子系統的名字。
param name,param value:參數的名字和參數的值。
                   若是沒有group,則就沒有group被建立。
Default段以下面的形式:
default {
                     perm {
                            task {
                                   uid = <task user>;
                                   gid = <task group>;
                                   fperm = <file permissions>
                            }
                            admin {
                                   uid = <admin name>;
                                   gid = <admin group>;
                                   dperm = <directory permissions>
                                   fperm = <file permissions>
                            }
                     }
              }
下面舉兩個例子:
mount {#定義須要建立的cgroup子系統及其掛載點,這裏建立cpu與cpuacct(統計)兩個cgroup子系統
                     cpu = /mnt/cgroups/cpu;
                     cpuacct = /mnt/cgroups/cpu;
              }
和下面的shell腳本是等價的:
   mkdir /mnt/cgroups/cpu
   mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/c
group daemons/www {
                     perm {#定義組的權限
                            task {
                                   uid = root;
                                   gid = webmaster;
                                   fperm = 770;
                            }
                            admin {
                                   uid = root;
                                   gid = root;
                                   dperm = 775;
                                   fperm = 744;
                            }
                     }
                     cpu {
                            cpu.shares = "1000";
                     }
              }
 
              group daemons/ftp {
                     perm {
                            task {
                                   uid = root;
                                   gid = ftpmaster;
                                   fperm = 774;
                            }
                            admin {
                                   uid = root;
                                   gid = root;
                                   dperm = 755;
                                   fperm = 700;
                            }
                     }
                     cpu {
                            cpu.shares = "500";
                     }
              }
至關於使用下面的腳本:
mkdir /mnt/cgroups/cpu
              mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/cpu
 
              mkdir /mnt/cgroups/cpu/daemons
 
              mkdir /mnt/cgroups/cpu/daemons/www
              chown root:root /mnt/cgroups/cpu/daemons/www/*
              chown root:webmaster /mnt/cgroups/cpu/daemons/www/tasks
              echo 1000 > /mnt/cgroups/cpu/daemons/www/cpu.shares
                   上面的具體內容能夠參考,cfconfig.conf文件說明
1.4 用戶空間掛載Cgroup
                   上面咱們分析了一下,cgroup的配置文件,這裏咱們具體分析一下使用命令如何進行配置。咱們知道cgroup的實現有一個文件系統的支持,用戶空間的配置可使用cgroup文件系統。首先,咱們能夠建立一個層級:在建立層級以前咱們須要建立掛載的目錄,這裏使用的目錄是/home/ubuntu /test_cgroup
root@ubuntu:~# mount -t cgroup -o cpu cpu_group /home/ubuntu/test_cgroup/
這個命令就是建立了一個test_cgroup的層級,這個層級有一個子系統cpu,並把層級掛載到了/home/ubuntu /test_cgroup目錄下。進入該目錄能夠看到一些和CPU相關的參數。
root@ubuntu:~# cd test_cgroup/
root@ubuntu:~/test_cgroup# ls
cgroup.clone_children  cpu.cfs_period_us  cpu.shares         tasks
cgroup.event_control   cpu.cfs_quota_us   cpu.stat       cgroup.procs           cpu.rt_period_us   notify_on_release
cgroup.sane_behavior   cpu.rt_runtime_us  release_agent
而後建立一個cgroup,名字爲foo
root@ubuntu:~/test_cgroup# mkdir foo
root@ubuntu:~/test_cgroup# cd foo/
root@ubuntu:~/test_cgroup/foo# ls
cgroup.clone_children  cpu.cfs_period_us  cpu.rt_runtime_us  notify_on_release
cgroup.event_control   cpu.cfs_quota_us   cpu.shares         tasks
cgroup.procs           cpu.rt_period_us   cpu.stat
             這樣就在cpu_group層級上建立了一個foo的cgroup,在Foo目錄下有一些文件,這些都是CPU相關的屬性。其中cat ~/test_cgroup/task能夠看到系統中的全部進程ID。這是由於每建立一個層級,系統會把系統中因此的進程ID添加到task中,而在foo/task文件倒是空,這個文件用戶能夠添加。
在/proc/下面有一個cgroups的文件,記錄了全部cgroups子系統的狀態信息。
root@ubuntu:~/test_cgroup/foo# cat /proc/cgroups
#subsys_name    hierarchy num_cgroups            enabled
cpuset                   3                 1                 1
cpu      4                 3                 1
cpuacct                 5                 1                 1
memory                6                 2                 1
devices                  7                 1                 1
freezer                  8                 1                 1
blkio    9                 1                 1
perf_event           10              1                 1
hugetlb                  11              1                 1
             從左到右的條目分別是子系統name,hierarchy ID,子系統的cgroup控制組數目,子系統是否可用(1可用,0不可用)
/proc/mounts文件顯示了系統中掛載的文件系統信息,前面幾個目錄表示文件系統name,掛載點絕對路徑,文件系統類型
root@ubuntu:~/test_cgroup/foo# cat /proc/mounts
rootfs / rootfs rw 0 0
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
udev /dev devtmpfs rw,relatime,size=503368k,nr_inodes=125842,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /run tmpfs rw,nosuid,noexec,relatime,size=102556k,mode=755 0 0
/dev/disk/by-uuid/612dacd9-3cf7-471b-92a4-f5c7c6e4e88a / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
none /sys/fs/cgroup tmpfs rw,relatime,size=4k,mode=755 0 0
none /sys/fs/fuse/connections fusectl rw,relatime 0 0
none /sys/kernel/debug debugfs rw,relatime 0 0
none /sys/kernel/security securityfs rw,relatime 0 0
none /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0
none /run/shm tmpfs rw,nosuid,nodev,relatime 0 0
none /run/user tmpfs rw,nosuid,nodev,noexec,relatime,size=102400k,mode=755 0 0
none /sys/fs/pstore pstore rw,relatime 0 0
systemd /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,name=systemd 0 0
vmware-vmblock /run/vmblock-fuse fuse.vmware-vmblock rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other 0 0
gvfsd-fuse /run/user/1000/gvfs fuse.gvfsd-fuse rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/cpu cgroup rw,relatime,cpu 0 0
cgroup /sys/fs/cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,relatime,freezer 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,relatime,blkio 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,relatime,perf_event 0 0
cgroup /sys/fs/cgroup/hugetlb cgroup rw,relatime,hugetlb 0 0
gvfsd-fuse /root/.gvfs fuse.gvfsd-fuse rw,nosuid,nodev,relatime,user_id=0,group_id=0 0 0
test_group /home/zfz/cgroup cgroup rw,relatime,cpu 0 0
cpu_group /home/zfz/test_cgroup cgroup rw,relatime,cpu 0 0
1.5  Cgroup使用實例
用lssubsys -al來列出系統支持多少種子系統,和使用ls /sys/fs/cgroup/ (ubuntu)來顯示已經掛載的子系統。
若是提示下面的錯誤信息,則表示系統中尚未安裝cgroup.
lssubsys -all
The program 'lssubsys' is currently not installed. You can install it by typing:
                   須要使用下面的方法進行安裝:
root@ubuntu:~# apt-get install cgroup-bin
Reading package lists... Done
                   再次使用lssubsys列出系統中支持的子系統,根據不一樣的內核版本,支持的子系統也不相同。
root@ubuntu:~# lssubsys --all
cpuset
cpu
cpuacct
memory
devices
freezer
blkio
perf_event
hugetlb
                   還有一種狀況須要進行確認,確認相應的內核部分是否已經編譯。
grep CGROUP /boot/config-`uname -r`
CONFIG_CGROUPS=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NET_CLS_CGROUP=m
CONFIG_NETPRIO_CGROUP=m
                   咱們能夠建立一個cgroup的cpu子系統,建立完成以後就在該目錄下有下面的屬性文件能夠進行設置。
   root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# ls
cgroup.clone_children  cpu.cfs_period_us  cpu.rt_runtime_us  notify_on_release
cgroup.event_control   cpu.cfs_quota_us   cpu.shares         tasks
cgroup.procs           cpu.rt_period_us   cpu.stat
                   使用cat命令查看其中的默認值。
root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat cpu.cfs_quota_us
-1
root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat cpu.cfs_period_us
100000
默認掛載在/sys/fs/cgroup/memory,能夠經過cfconfig.conf文件查看默認的掛載點。這裏有兩個小的例子主要是爲了測試cgroup對進程使用CPU和memeory的控制,這裏使用兩個Python腳原本模擬其中的效果。
例子1:設置該進程對CPU的佔用率不能超過50%。
root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# echo 50000 > cpu.cfs_quota_us
root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat cpu.cfs_quota_us
50000
root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# cat tasks
root@ubuntu:/sys/fs/cgroup/cpu/test_cpu# echo 9477 > tasks
使用的Python程序以下:
root@ubuntu:~# cat python_test_cpu.py
#!/usr/bin/env python
import os
pid_num = os.getpid()
print pid_num
var = 1
count = 1
while var == 1:
    count = count + 1
count = 0
 
在沒有把python的進程號添加到tasks中,該進程的CPU佔用率接近95%。而把該進程ID添加到tasks中通過持續的觀察,該進程的CPU使用率不超出50%,和在cgroup中設置的一致。

例子2:限制內存的使用率
                   Python代碼以下:
root@ubuntu:~# cat python_test_memory.py
#!/usr/bin/env python
import os
import time
pid_num = os.getpid()
print pid_num
var = 1
a = "abcdefgh"
b = "abcdefgh"
c = ""
time.sleep(10)
#while var == 1:
for i in range(1,30000000):
    c = "####".join([a,b]) + c
                   在沒有使用cgroups機制的狀況下,經過top命令查看該進程佔用的memory狀況以下:

持續觀察一段時間基本維持在40%左右。在使用cgoup機制,限制在10M的狀況下,其內存的佔有率發生了變化。
root@ubuntu:/sys/fs/cgroup/memory/memory_test# echo 10M > memory.limit_in_bytes
root@ubuntu:/sys/fs/cgroup/memory/memory_test# cat memory.limit_in_bytes
10485760

                   過一小段時間會出現進程退出的狀況,以下:進程被殺掉了。
root@ubuntu:~# ./python_test_memory.py
10608
[8]+  Killed                  ./python_test_memory.py
Killed
 在這裏也能夠配置內核的OOM機制,默認值是開着呢。
root@ubuntu:/sys/fs/cgroup/memory/memory_test# cat memory.oom_control
oom_kill_disable 0
under_oom 0
             在上面咱們設置的是memory.limit_in_bytes 值,但在目錄下還有一個memory.soft_limit_in_bytes 屬性,,該值和 memory.limit_in_bytes 的差別是,memory.soft_limit_in_bytes這個限制並不會阻止進程使用超過限額的內存,只是在系統內存不足時,會優先回收超過限額的進程佔用的內存,使之向限定值靠攏
經過上面的分析能夠看出來,簡單的說Cgroup就是限制了各個不一樣進程之間使用各類資源的能力。上面兩個例子是最經常使用的CPU和內存,每個內核子系統都有不少的配置選項信息,其中配置選項的含義能夠參考Linux內核文檔,Linux的Cgroup子系統解釋。Cgroup作到對資源的限制訪問,這對於Linux系統上的虛擬化和雲計算提供了一種資源配置方式。
參考文獻:
http://blog.chinaunix.net/uid-20940095-id-3294134.html
http://files.cnblogs.com/lisperl/cgroups介紹.pdf
相關文章
相關標籤/搜索