新版内核普遍采用 v2 版本的 cgroup

是什么

cgroup 既 Controll group, 是 linux 对外提供的文件接口,用来控制进程资源。

$ mount -t cgroup2

cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot,memory_hugetlb_accounting)

使用

新建 group

直接在 /sys/fs/cgroup 下新建目录

$ cd /sys/fs/cgroup/
$ sudo mkdir test
$ ls ./test
cgroup.controllers      cpu.stat             memory.peak
cgroup.events           cpu.stat.local       memory.pressure
cgroup.freeze           cpu.uclamp.max       memory.reclaim
cgroup.kill             cpu.uclamp.min       memory.stat
cgroup.max.depth        cpu.weight           memory.swap.current
cgroup.max.descendants  cpu.weight.nice      memory.swap.events
cgroup.procs
...

重点关注 cgroup.procs 这个文件, 其中的内容(pid)既我们想要控制的进程号。

控制cpu占用率

$ while true; do : ; done &
[1] 50274 # 50274 为对应pid
$ top -b -n 1 -p 50274 | grep "50274" | awk '{print $9}'
99.7 # 此时没有限制,死循环占用100%的cpu
$ echo 50274 | sudo tee cgroup.procs # 直接使用当前shell的进程号, 这样子随后开启的子进程也会受到控制
$ echo 2000 10000 | sudo tee cpu.max # 10000 微秒内 `$$` 进程只能占用 2000 微秒
$ top -b -n 1 -p 50274 | grep "50274" | awk '{print $9}'
19.9 # 20%

控制内存

测试程序

//filepath: ./test_mem.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MB (1024 * 1024)

int main() {
  char *p;
  int i = 0;

  while (1) {
    p = (char *)malloc(MB);
    memset(p, 0, MB);
    printf("%d MB allocated\n", ++i);
    sleep(1);
  }
  return 0;
}
gcc ./test_mem.c -o test_mem

test_mem 每隔一秒就申请1 MB 内存并填充(一定要使用 memset 填充,否则会写入虚拟内存,不计入物理内存/交换空间)

$ echo $$ | sudo tee cgroup.procs # 将当前shell的pid传入,shell的子进程(test_mem)也会受限制
$ echo $(( 5 * 1024 * 1024 )) | sudo tee memory.max
$ echo 0 | sudo tee memory.swap.max # 禁用 swap
$ ./test_mem
1 MB allocated
2 MB allocated
...
10 MB allocated
(shell exit)

参考