環境:Centos 7 64
一、對某個進程限制它使用cpu為50%
1、先寫一個占用cpu較高的腳本
x=0 while [ True ];do x=$x+1 done;
2、可以看到運行后cpu使用到了100%
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 20369 root 20 0 113452 1664 1196 R 100.0 0.0 0:10.73 sh
3、創建控制組
mkdir /sys/fs/cgroup/cpu/foo
4、下面用cgroups控制這個進程的cpu資源
echo 50000 > /sys/fs/cgroup/cpu/foo/cpu.cfs_quota_us #將cpu.cfs_quota_us設為50000,相對於cpu.cfs_period_us的100000是50%
echo 20369 >/sys/fs/cgroup/cpu/foo/tasks
5、我們看到大概限制到了50%左右
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20369 root 20 0 113828 1908 1196 R 49.8 0.0 0:33.75 sh
6、cgroup控制組下還有很多對於cpu其他的一些控制
[root@foreman ~]# ls /sys/fs/cgroup/cpu/foo/ cgroup.clone_children cpuacct.usage cpu.rt_period_us notify_on_release cgroup.event_control cpuacct.usage_percpu cpu.rt_runtime_us tasks cgroup.procs cpu.cfs_period_us cpu.shares cpuacct.stat cpu.cfs_quota_us cpu.stat
ls /sys/fs/cgroup/memory/cgtest/*
cgroup.event_control #用於eventfd的接口 memory.usage_in_bytes #顯示當前已用的內存 memory.limit_in_bytes #設置/顯示當前限制的內存額度 memory.failcnt #顯示內存使用量達到限制值的次數 memory.max_usage_in_bytes #歷史內存最大使用量 memory.soft_limit_in_bytes #設置/顯示當前限制的內存軟額度 memory.stat #顯示當前cgroup的內存使用情況 memory.use_hierarchy #設置/顯示是否將子cgroup的內存使用情況統計到當前cgroup里面 memory.force_empty #觸發系統立即盡可能的回收當前cgroup中可以回收的內存 memory.pressure_level #設置內存壓力的通知事件,配合cgroup.event_control一起使用 memory.swappiness #設置和顯示當前的swappiness memory.move_charge_at_immigrate #設置當進程移動到其他cgroup中時,它所占用的內存是否也隨着移動過去 memory.oom_control #設置/顯示oom controls相關的配置 memory.numa_stat #顯示numa相關的內存
寫一個內存占用的c程序,每秒申請1MB內存
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MB (1024 * 1024) int main(int argc, char *argv[]) { char *p; int i = 0; while(1) { p = (char *)malloc(MB); memset(p, 0, MB); printf("%dM memory allocated\n", ++i); sleep(1); } return 0; }
#gcc mem-allocate.c -o mem-allocate
cgroup限制內存使用50M(強制限制 memory.limit_in_bytes)
[root@foreman cgtest]# pwd /sys/fs/cgroup/memory/cgtest [root@foreman cgtest]# echo 50M > memory.limit_in_bytes [root@foreman cgtest]# echo 0 > memory.oom_control [root@foreman cgtest]# pgrep mem-allocate 35190 [root@foreman cgtest]# echo 35190 > tasks #只對一個線程ID做限制 ,如果需要對一個線程組做限制,需要將PID放到cgroup.procs中。
這樣這個PID本身以及所衍生的進程整體會限制在memory.limit_in_bytes中設置的大小內存
同時包括這個PID調用所產生的進程也會受到限制。想查看某個進程所屬線程組使用如下命令
#cat /proc/<PID>/cgroup 來進行查看
限制效果:
[root@foreman ~]# ./mem-allocate 1M memory allocated 2M memory allocated 3M memory allocated 4M memory allocated ... ... 49M memory allocated 50M memory allocated 51M memory allocated Killed
如果達到限制不想直接kill進程,而是掛起進程需要將oom_kill_disable 設置為1 [root@foreman cgtest]#cat memory.oom_control #默認 oom_kill_disable 0 under_oom 0 [root@foreman cgtest]# echo 1 > memory.oom_control [root@foreman cgtest]# cat memory.oom_control oom_kill_disable 1 under_oom 0
跑一個腳本使其產生多個子線程去瘋狂吃內存(提前將memory.limitxxxxx設置為300MB,oom_kill 設置為0)
[root@foreman ~]# cat cgtest.sh sleep 20 x=0 while [ True ];do nohup /root/mem-allocate >>/root/mem.log 2>&1 & sleep 1 proc_num=$(pgrep mem-allocate | wc -l) if [ $proc_num -eq 50 ];then sleep 1000000 fi x=$(($x+1)) done;
跑起來后用systemd-cgtop查看限制情況:
#systemd-cgtop #使用此命令查看cgroup限制的資源情況 /cgtest 25 - 295.8M 通過上面可以清晰的看到tasks 25個 內存限制到了300MB
概念理解:
就把 5678 進程加入到了 /foo 控制組。那么 tasks 和 cgroups.procs 有什么區別呢?前面說的對“進程”的管理限制其實不夠准確。系統對任務調度的單位是線程。
在這里,tasks 中看到的就是線程 id。而 cgroups.procs 中是線程組 id,也就是一般所說的進程 id 。
將一個一般的 pid 寫入到 tasks 中,只有這個 pid 對應的線程,以及由它產生的其他進程、線程會屬於這個控制組,原有的其他線程則不會。
而寫入 cgroups.procs 會把當前所有的線程都加入進去。如果寫入 cgroups.procs 的不是一個線程組 id,而是一個一般的線程 id,那會自動找到所對應的線程組 id 加入進去。
進程在加入一個控制組后,控制組所對應的限制會即時生效。想知道一個進程屬於哪些控制組,可以通過 cat /proc/<pid>/cgroup 查看。 要把進程移出控制組,把 pid 寫入到根 cgroup 的 tasks 文件即可。因為每個進程都屬於且只屬於一個 cgroup,加入到新的 cgroup 后,原有關系也就解除了。
要刪除一個 cgroup,可以用 rmdir 刪除相應目錄。不過在刪除前,必須先讓其中的進程全部退出,對應子系統的資源都已經釋放,否則是無法刪除的。 前面都是通過文件系統訪問方式來操作 cgroups 的。實際上,也有一組命令行工具。