一、Linux control groups
簡介
- Resource limitation: 限制資源使用,比如內存使用上限以及文件系統的緩存限制。
- Prioritization: 優先級控制,比如:CPU利用和磁盤IO吞吐。
- Accounting: 一些審計或一些統計,主要目的是為了計費。
- Control: 掛起進程,恢復執行進程。
CGroup的術語
-
blkio — 這個子系統為塊設備設定輸入/輸出限制,比如物理設備(磁盤,固態硬盤,USB 等等)。
-
cpu — 這個子系統使用調度程序提供對 CPU 的 cgroup 任務訪問。
-
cpuacct — 這個子系統自動生成 cgroup 中任務所使用的 CPU 報告。
-
cpuset — 這個子系統為 cgroup 中的任務分配獨立 CPU(在多核系統)和內存節點。
-
devices — 這個子系統可允許或者拒絕 cgroup 中的任務訪問設備。
-
freezer — 這個子系統掛起或者恢復 cgroup 中的任務。
-
memory — 這個子系統設定 cgroup 中任務使用的內存限制,並自動生成內存資源使用報告。
-
net_cls — 這個子系統使用等級識別符(classid)標記網絡數據包,可允許 Linux 流量控制程序(tc)識別從具體 cgroup 中生成的數據包。
-
net_prio — 這個子系統用來設計網絡流量的優先級
-
hugetlb — 這個子系統主要針對於HugeTLB系統進行限制,這是一個大頁文件系統。
操作接口
在linux系統中一皆文件,當然對CGroup的接口操作也是通過文件來實現的,我們可以通過mount命令查看其掛載目錄:
以上目錄都可以是限制的對象,也就是對應的術語中的各個子系統。例如查看這里的CPU限制目錄:
如果你熟悉CPU管理的話,cfs_period 和 cfs_quota兩個可能不會陌生,這兩個參數需要組合使用,可以用來限制進程在長度為cfs_period 的一段時間內,只能被分配到總量為cfs_quota 的 CPU 時間。以下示例將會演示如何限制。
限制CPU
限制CPU的使用需要在子系統目錄(/sys/fs/cgroup/cpu)下創建目錄,這里創建一個cpu_limit_demo目錄:
可以看到當我們在CPU子系統下創建目錄時候,其對應的限制配置文件會自動進行創建,現在在后台寫個死循環跑滿CPU:
此時使用top命令查看pid為10069的進程CPU使用狀況:

cpu.cfs_quota_us值為-1代表沒有任何限制,cpu.cfs_period_us 則是默認的 100 ms,即100000us,下面將向cpu_limit_demo控制組的cpu.cfs_quota_us文件寫入50ms即50000us,這表示在100ms周期內,cpu最多使用%50,同時將該進程的pid號為10069寫入對應的tasks文件,表示對那個進程限制:
於是pid為10069的進程cpu就被限制成了%Cpu :50.0 us,此時利用top在此查看cpu使用情況(top后按1可看到每個邏輯cpu具體使用):
以上可以看到此時pid10069的進程使用率已經變成了50%了,說明限制生效了。同樣的道理,在/sys/fs/cgroup下的子系統都可以限制不通的資源使用如Block IO、Memory等。
限制內存
首先在 /sys/fs/cgroup/memory 下新建一個名為 limit_memory_demo 的 cgroup:
mkdir /sys/fs/cgroup/memory/limit_memory_demo
限制該 cgroup 的內存使用量為 500 MB:
# 物理內存500M(下面單位Byte) MB並且不使用swap echo 524288000 > /sys/fs/cgroup/memory/limit_memory/memory.limit_in_bytes echo 0 > /sys/fs/cgroup/memory/limit_memory/memory.swappiness
最后將需要限制的進程號的pid寫入task文件就可以了:
echo [pid] > /sys/fs/cgroup/memory/limit_memory_demo/tasks
限制磁盤IO
使用dd寫到null設備:
[root@app51 blkio]# dd if=/dev/sda of=/dev/null bs=1M
使用iotop(安裝使用yum install -y iotop)查看io速率,此時讀的速率為2.17G/s
創建一個blkio(塊設備IO)的cgroup,並查看設備號,然后將pid和限制的設備以及速度寫入文件:

mkdir /sys/fs/cgroup/blkio/ echo '8:0 1048576' > /sys/fs/cgroup/blkio/limit_io/blkio.throttle.read_bps_device echo [pid] > /sys/fs/cgroup/blkio/limit_io/tasks
二、 Docker中資源限制原理
在了解了Cgroup對資源的限制方法,再來理解Docker中的資源限制其實就變的容易了。默認情況下,Docker會在需要限制的子系統下創建一個目錄為docker的控制組如下:
當容器運行后,會在這些目錄生成以容器ID為目錄的子目錄用於限制的容器資源。例如,以cpu為例,docker run啟動參數中--cpu-quota 參數可以指定默認時間內使用的cpu:
[root@app51 docker]# docker run -d --name nginx-c1 --cpu-quota 50000 nginx:latest e9432a513e4bed0a744a29a8eaba2b27d9e40efabfe479d19d32f9558888ed29 [root@app51 docker]#
此時我們查看cpu對應的容器資源限制:
[root@app51 docker]# cd /sys/fs/cgroup/cpu/docker/ [root@app51 docker]# cat e9432a513e4bed0a744a29a8eaba2b27d9e40efabfe479d19d32f9558888ed29/cpu.cfs_quota_us 50000 [root@app51 docker]# cat e9432a513e4bed0a744a29a8eaba2b27d9e40efabfe479d19d32f9558888ed29/tasks 10561 10598
從上面結果我們能看出,docker run的啟動限制參數值,被注入到了Cgroups的cpu控制組的對應配置文件中了。同時還有看到有兩個進程同時被限制了,這是因為我們啟動的nginx,nginx的主進程會啟動多個子進程,使用ps -ef可以查看:
[root@app51 docker]# ps -ef |grep 10561 root 10561 10544 0 16:32 ? 00:00:00 nginx: master process nginx -g daemon off; 101 10598 10561 0 16:32 ? 00:00:00 nginx: worker process root 10614 10179 0 16:38 pts/2 00:00:00 grep --color=auto 10561 [root@app51 docker]#
不難看到,其中主進程為10561(nginx master),子進程為10598(nginx worker)。以上則是docker的資源限制原理。Docker對資源限制主要是CPU和內存,其中還有很多參數可以使用,以下將會介紹docker中CPU和MEMERY限制參數。
三、CPU限制參數
默認情況下,容器的資源是不受限制的,宿主機提供多少資源,容器就可以使用多少資源,如果不對容器做資源限制,很有可能一個或幾個容器把宿主機的資源耗盡,而導致應用或者服務不可用。所以對容器資源的限制顯得非常重要,而docker主要提供兩種類別的資源限制:CPU和內存,通過docker run 時指定參數實現。cpu限制資源限制有多種維度,以下將詳細介紹。
限制cpu配額
docker run -d --cpu-period=100000 --cpu-quota=250000 --name test-c1 nginx:latest
限制cpu可用數量
[root@app51 ~]# docker run -d --cpus=2 --name test-c2 nginx:latest 5347269d0974e37af843b303124d8799c6f4336a14f61334d21ce9356b1535bc
使用固定的cpu
通過--cpuset-cpus參數指定,表示指定容器運行在某個或某些個固定的cpu上,多個cpu使用逗號隔開。例如四個cpu,0代表第一個cpu,--cpuset-cpus=1,3代表該容器只能運行在第二個或第四個cpu上。查看cpu可以通過cat /proc/cpuinfo查看。
示例:
[root@app51 ~]# docker run -d --cpuset-cpus=1,3 --name test-c3 nginx:latest
276056fce04982c2de7969ca309560ce60b0ebf960cf7197808616d65aa112d4
設置CPU比例(權重)
[root@app51 ~]# docker run -d --cpu-shares=2048 --name test-c4 nginx:latest 578506d61324b38d7a01bf1d2ec87cb5d1ab50276ef6f7b28858f2d2e78b2860 [root@app51 ~]# docker run -d --cpu-shares=4096 --name test-c5 nginx:latest d56a90bf080b70d11d112468348874e48fe4a78d09d98813a0377b34fa382924
四、 MEMORY限制參數
內存是一種不可壓縮資源,一旦某個進程或者容器中應用內存不足就會引起OOM異常(Out Of Memory Exception),這將導致應用不可用,並且在Linux主機上,如果內核檢測到沒有足夠的內存來執行重要的系統功能,系統會按照一定優先級殺死進程來釋放系統內存。docker對內存的限制分為swap限制和物理內存限制,單位可以使用b,k, m,g。
限制最大物理內存使用
通過-m或者—memory指定,是硬限制,如果設置此選項,則允許設置的最小值為4m,該參數是最常用參數。
示例:
[root@app51 ~]# docker run -d --memory=512m --name mem-c1 nginx:latest 67b0cb645c401bc6df3235d27d629185870716351396c71dfa3877abbbd377c8
限制swap使用
- --memory-swap 設置為正整數,那么這兩個--memory和 --memory-swap 必須設置。--memory-swap 表示可以使用的memory 和 swap,並且--memory控制非交換內存(物理內存)使用的量。列如--memory=300m 和--memory-swap=1g,容器可以使用300m的內存和700m(1g - 300m)swap。
- --memory-swap 設置為0,則忽略該設置,並將該值視為未設置。
- --memory-swap 設置為與值相同的值--memory,並且--memory設置為正整數,則容器不能使用swap,可以通過此方法限制容器不使用swap。
- --memory-swap 未設置並--memory 設置,則容器可以使用兩倍於--memory設置的swap,主機容器需要配置有swap。例如,如果設置--memory="300m" 和--memory-swap 未設置,容器可以使用300m的內存和600m的swap。
- --memory-swap 設置為-1,則允許容器使用無限制swap,最多可達宿主機系統上可用的數量。
示例:
[root@app51 ~]# docker run -d --memory=512m --memory-swap=512m --name mem-c2 nginx:latest 6b52c015a53be2c3e0e509eea918125a760c1c14df4cc977f05b5b31b83161d5
其他
- --oom-kill-disable :默認情況下,如果發生內存不足(OOM)錯誤,內核會終止容器中的進程,如要更改此行為,使用該--oom-kill-disable選項,但是該選項有個前提就是-m選項必須設置。
- --memory-swappiness:默認情況下,容器的內核可以交換出一定比例的匿名頁。--memory-swappiness就是用來設置這個比例的。--memory-swappiness可以設置為從 0 到 100。0 表示關閉匿名頁面交換。100 表示所有的匿名頁都可以交換。默認情況下,如果不適用--memory-swappiness,則該值從父進程繼承而來。
- --memory-reservation:Memory reservation 是一種軟性限制,用於限制物理內存的最大用值,它只是確保容器不會長時間占用超過--memory-reservation限制的內存大小。給--memory-reservation設置一個比-m小的值后,雖然容器最多可以使用-m使用的內存大小,但在宿主機內存資源緊張時,在系統的下次內存回收時,系統會回收容器的部分內存頁,強迫容器的內存占用回到--memory-reservation設置的值大小。
五、總結