您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么通過 Cgroups 機制實現資源限制”,在日常操作中,相信很多人在怎么通過 Cgroups 機制實現資源限制問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么通過 Cgroups 機制實現資源限制”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
cgroups(全稱:control groups)是 Linux 內核的一個功能,它可以實現限制進程或者進程組的資源(如 CPU、內存、磁盤 IO 等)。
在 2006 年,Google 的工程師( Rohit Seth 和 Paul Menage 為主要發起人) 發起了這個項目,起初項目名稱并不是cgroups,而被稱為進程容器(process containers)。在 2007 年cgroups代碼計劃合入Linux 內核,但是當時在 Linux 內核中,容器(container)這個詞被廣泛使用,并且擁有不同的含義。為了避免命名混亂和歧義,進程容器被重名為cgroups,并在 2008 年成功合入 Linux 2.6.24 版本中。cgroups目前已經成為 systemd、Docker、Linux Containers(LXC) 等技術的基礎。
cgroups 主要提供了如下功能:
資源限制: 限制資源的使用量,例如我們可以通過限制某個業務的內存上限,從而保護主機其他業務的安全運行。
優先級控制:不同的組可以有不同的資源( CPU 、磁盤 IO 等)使用優先級。
審計:計算控制組的資源使用情況。
控制:控制進程的掛起或恢復。
cgroups功能的實現依賴于三個核心概念:子系統、控制組、層級樹。
子系統(subsystem):是一個內核的組件,一個子系統代表一類資源調度控制器。例如內存子系統可以限制內存的使用量,CPU 子系統可以限制 CPU 的使用時間。
控制組(cgroup):表示一組進程和一組帶有參數的子系統的關聯關系。例如,一個進程使用了 CPU 子系統來限制 CPU 的使用時間,則這個進程和 CPU 子系統的關聯關系稱為控制組。
層級樹(hierarchy):是由一系列的控制組按照樹狀結構排列組成的。這種排列方式可以使得控制組擁有父子關系,子控制組默認擁有父控制組的屬性,也就是子控制組會繼承于父控制組。比如,系統中定義了一個控制組 c1,限制了 CPU 可以使用 1 核,然后另外一個控制組 c2 想實現既限制 CPU 使用 1 核,同時限制內存使用 2G,那么 c2 就可以直接繼承 c1,無須重復定義 CPU 限制。
cgroups 的三個核心概念中,子系統是最核心的概念,因為子系統是真正實現某類資源的限制的基礎。
下面我通過一個實例演示一下在 Linux 上默認都啟動了哪些子系統。我們先通過 mount 命令查看一下當前系統已經掛載的cgroups信息:
root@cr7-ubuntu:~# mount -t cgroup cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct) cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer) cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
通過輸出,可以看到當前系統已經掛載了我們常用的cgroups子系統,例如 cpu、memory、pids 等我們常用的cgroups子系統。這些子系統中,cpu 和 memory 子系統是容器環境中使用最多的子系統,下面我對這兩個子系統做詳細介紹。
首先我們在沒有限制CPU使用率的情況下在后臺執行這樣一條腳本:
root@cr7-ubuntu:~# while : ; do : ; done & [1] 839960
顯然,它執行了一個死循環,可以把計算機的 CPU 吃到 100%,根據它的輸出,我們可以看到這個腳本在后臺運行的進程號(PID)是 839960。
我們可以用 top 指令來確認一下 CPU 有沒有被打滿:
在輸出里可以看到,CPU 的使用率已經 100% 了(%Cpu(s): 98.0 us)。
現在我們 以 cpu 子系統為例,演示一下cgroups如何限制進程的 cpu 使用時間。由于cgroups的操作很多需要用到 root 權限,我們在執行命令前要確保已經切換到了 root 用戶,以下命令的執行默認都是使用 root 用戶。
第一步:在 cpu 子系統下創建 cgroup cgroups的創建很簡單,只需要在相應的子系統下創建目錄即可。下面我們到 cpu 子系統下創建測試文件夾:
root@cr7-ubuntu:~# mkdir /sys/fs/cgroup/cpu/mydocker
這個目錄就稱為一個“控制組”。你會發現,操作系統會在你新創建的 container 目錄下,自動生成該子系統對應的資源限制文件:
root@cr7-ubuntu:~# ls -l /sys/fs/cgroup/cpu/mydocker total 0 -rw-r--r-- 1 root root 0 Mar 10 09:34 cgroup.clone_children -rw-r--r-- 1 root root 0 Mar 10 09:34 cgroup.procs -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.stat -rw-r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage_all -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage_percpu -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage_percpu_sys -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage_percpu_user -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage_sys -r--r--r-- 1 root root 0 Mar 10 09:34 cpuacct.usage_user -rw-r--r-- 1 root root 0 Mar 10 09:34 cpu.cfs_period_us -rw-r--r-- 1 root root 0 Mar 10 09:34 cpu.cfs_quota_us -rw-r--r-- 1 root root 0 Mar 10 09:34 cpu.shares -r--r--r-- 1 root root 0 Mar 10 09:34 cpu.stat -rw-r--r-- 1 root root 0 Mar 10 09:34 cpu.uclamp.max -rw-r--r-- 1 root root 0 Mar 10 09:34 cpu.uclamp.min -rw-r--r-- 1 root root 0 Mar 10 09:34 notify_on_release -rw-r--r-- 1 root root 0 Mar 10 09:34 tasks
你會在它的輸出里注意到 cfs_period 和 cfs_quota 這樣的關鍵詞。這兩個參數需要組合使用,可以用來限制進程在長度為 cfs_period 的一段時間內,只能被分配到總量為 cfs_quota 的 CPU 時間。 如果用這個值去除以調度周期(也就是 cpu.cfs_period_us),50ms/100ms = 0.5,這樣這個控制組被允許使用的 CPU 最大配額就是 0.5 個 CPU。從這里能夠看出,cpu.cfs_quota_us 是一個絕對值。如果這個值是 200000,也就是 200ms,那么它除以 period,也就是 200ms/100ms=2,結果超過了 1 個 CPU,這就意味著這時控制組需要 2 個 CPU 的資源配額。
而此時,我們可以通過查看 mydocker 目錄下的文件,看到 mydocker 控制組里的 CPU quota 還沒有任何限制(即:-1),CPU period 則是默認的 100 ms(100000 us):
root@cr7-ubuntu:~# cat /sys/fs/cgroup/cpu/mydocker/cpu.cfs_quota_us -1 root@cr7-ubuntu:~# cat /sys/fs/cgroup/cpu/mydocker/cpu.cfs_period_us 100000
第二步:設置限制參數
接下來,我們可以通過修改這些文件的內容來設置限制。向 mydocker 組里的 cfs_quota 文件寫入 20 ms(20000 us):
root@cr7-ubuntu:~# echo 20000 > /sys/fs/cgroup/cpu/mydocker/cpu.cfs_quota_us
它意味著在每 100 ms 的時間里,被該控制組限制的進程只能使用 20 ms 的 CPU 時間,也就是說這個進程只能使用到 20% 的 CPU 帶寬。(如果CPU是多核,那么20%指的是這個進程在所有CPU中能使用的帶寬總和,例如CPU1是10%,CPU2是10%)
第三步:將進程加入cgroup控制組
接下來,我們把被限制的進程的 PID 寫入 mydocker 組里的 tasks 文件,上面的設置就會對該進程生效了:
root@cr7-ubuntu:~# echo 839960 > /sys/fs/cgroup/cpu/mydocker/tasks
此時我們用top命令查看一下: 可以看到,計算機的 CPU 使用率立刻降到了 20%(%Cpu0 : 21.5 us)。
第一步:在 memory 子系統下創建 cgroup
root@cr7-ubuntu:~# mkdir /sys/fs/cgroup/memory/mydocker
同樣,我們查看一下新創建的目錄下自動創建的文件:
root@cr7-ubuntu:~# ls -l /sys/fs/cgroup/memory/mydocker total 0 -rw-r--r-- 1 root root 0 Mar 10 09:50 cgroup.clone_children --w--w--w- 1 root root 0 Mar 10 09:50 cgroup.event_control -rw-r--r-- 1 root root 0 Mar 10 09:50 cgroup.procs -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.failcnt --w------- 1 root root 0 Mar 10 09:50 memory.force_empty -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.failcnt -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.limit_in_bytes -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.max_usage_in_bytes -r--r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.slabinfo -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.tcp.failcnt -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.tcp.limit_in_bytes -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.tcp.max_usage_in_bytes -r--r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.tcp.usage_in_bytes -r--r--r-- 1 root root 0 Mar 10 09:50 memory.kmem.usage_in_bytes -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.limit_in_bytes -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.max_usage_in_bytes -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.move_charge_at_immigrate -r--r--r-- 1 root root 0 Mar 10 09:50 memory.numa_stat -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.oom_control ---------- 1 root root 0 Mar 10 09:50 memory.pressure_level -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.soft_limit_in_bytes -r--r--r-- 1 root root 0 Mar 10 09:50 memory.stat -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.swappiness -r--r--r-- 1 root root 0 Mar 10 09:50 memory.usage_in_bytes -rw-r--r-- 1 root root 0 Mar 10 09:50 memory.use_hierarchy -rw-r--r-- 1 root root 0 Mar 10 09:50 notify_on_release -rw-r--r-- 1 root root 0 Mar 10 09:50 tasks
其中 memory.limit_in_bytes 文件代表內存使用總量,單位為 byte。
第二步:設置限制參數 例如,這里我希望對內存使用限制為 1G,則向 memory.limit_in_bytes 文件寫入 1073741824,命令如下:
root@cr7-ubuntu:~# echo 1073741824 > /sys/fs/cgroup/memory/mydocker/memory.limit_in_bytes
第三步:將進程加入cgroup控制組 把當前 shell 進程 ID 寫入 tasks 文件內:
root@cr7-ubuntu:~# echo $$ > /sys/fs/cgroup/memory/mydocker/tasks
這里我們需要借助一下工具 memtester,memtester 的安裝這里不再詳細介紹了。
安裝好 memtester 后,我們執行以下命令:
root@cr7-ubuntu:~# memtester 1500M 1 memtester version 4.2.2 (64-bit) Copyright (C) 2010 Charles Cazabon. Licensed under the GNU General Public License version 2 (only). pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 1500MB (1572864000 bytes) got 1500MB (1572864000 bytes), trying mlock ...Killed
該命令會申請 1500 M 內存,并且做內存測試。由于上面我們對當前 shell 進程內存限制為 1 G,當 memtester 使用的內存達到 1G 時,cgroup 便將 memtester 殺死。
上面最后一行的輸出結果表示 memtester 想要 1500 M 內存,但是由于 cgroup 限制,達到了內存使用上限,被殺死了,與我們的預期一致。
我們可以使用以下命令,降低一下內存申請,將內存申請調整為 500M:
root@cr7-ubuntu:~# memtester 500M 1 memtester version 4.2.2 (64-bit) Copyright (C) 2010 Charles Cazabon. Licensed under the GNU General Public License version 2 (only). pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 500MB (524288000 bytes) got 500MB (524288000 bytes), trying mlock ...locked. Loop 1/1: Stuck Address : ok Random Value : ok Compare XOR : ok Compare SUB : ok Compare MUL : ok Compare DIV : ok Compare OR : ok Compare AND : ok Sequential Increment: ok Solid Bits : ok Block Sequential : ok Checkerboard : ok Bit Spread : ok Bit Flip : ok Walking Ones : ok Walking Zeroes : ok 8-bit Writes : ok 16-bit Writes : ok Done.
這里可以看到,此時 memtester 已經成功申請到 500M 內存并且正常完成了內存測試。
上面創建的cgroups如果不想使用了,直接刪除創建的文件夾即可。 例如我想刪除內存下的 mydocker 目錄,使用以下命令即可:
root@cr7-ubuntu:~# rmdir /sys/fs/cgroup/memory/mydocker/
限制容器只能使用到 20% 的 CPU 帶寬。
root@cr7-ubuntu:~# docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
在啟動這個容器后,我們可以通過查看 Cgroups 文件系統下,CPU 子系統中,“docker”這個控制組里的資源限制文件的內容來確認:
root@cr7-ubuntu:~# cat /sys/fs/cgroup/cpu/docker/99cdb60e28191871c456f736470c9a1d344b95c6bcdb39036926428378db55c4/cpu.cfs_period_us 100000 root@cr7-ubuntu:~# cat /sys/fs/cgroup/cpu/docker/99cdb60e28191871c456f736470c9a1d344b95c6bcdb39036926428378db55c4/cpu.cfs_quota_us 20000
很長的數字+字母為容器的id,可以使用docker inspect <容器名>
命令來查看容器的id。
root@cr7-ubuntu:~# docker run -it -m=1g nginx
上述命令創建并啟動了一個 nginx 容器,并且限制內存為 1G。然后我們查看該容器對應的cgroup控制組 memory.limit_in_bytes 文件的內容,可以看到內存限制值正好為 1G:
root@cr7-ubuntu:~# cat /sys/fs/cgroup/memory/docker/2e5f7db4b9a08b08471b3fcf9f71cb14396fb081db3cdc25140714ae037f2136/memory.limit_in_bytes 1073741824
到此,關于“怎么通過 Cgroups 機制實現資源限制”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。