cgroups及相关工具
1. cgroups
1.1 cgroups介绍
cgroups(Control Groups)是 Linux 内核提供的一个功能,这个功能可以用来限制、控制与分离一个进程组的资源(如 CPU、内存、磁盘输入输出等)。本质上,cgroups 是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的。
1.2 cgroups功能
cgroups 可以为资源管理提供一个统一的框架,有以下功能:
-
限制进程组可以使用的资源数量(Resource limiting )
如限制进程组的内存使用上限/ CPU 使用限制,一旦进程组使用的内存达到限额再申请内存,,就会触发OOM(out of memory)。
-
进程组的优先级控制(Prioritization )
如限制进程组的 CPU 利用和磁盘 IO 吞吐。
-
记录进程组使用的资源数量(Accounting )
如记录某个进程组使用 CPU 的时间。
-
进程组控制(Control)
如挂起进程或恢复执行进程。
cgroups可以控制的子系统:
子系统 | 描述 |
---|---|
blkio | 对设备的 IO 进行限制。 |
cpu | 限制 CPU 时间片的分配。 |
cpuacct | 生成 cgroup 中的任务占用 CPU 资源的报告,与 cpu 挂载在同一目录。 |
cpuset | 给 cgroup 中的任务分配独立的 CPU 和内存节点。 |
devices | 限制设备文件的创建和对设备文件的读写。 |
freezer | 暂停或恢复 cgroup 中的任务。 |
memory | 对 cgroup 中的任务的可用内存进行限制,并自动生成资源占用报告。 |
perf_event | 允许 perf 观测 cgroup 中的 task。 |
net_cls | cgroup 中的任务创建的数据报文的类别标识符,让 Linux 流量控制器(tc 命令)可以识别来自特定 cgroup 任务的数据包,并进行网络限制。 |
hugetlb | 限制使用的内存页的数量。 |
pids | 限制任务的数量。 |
rdma | 限制 RDMA 资源(Remote Direct Memory Access,远程直接数据存储)。 |
1.3 cgroups信息查看
cgroups 版本查看
cat /proc/filesystems | grep
cgroups 子系统查看
cat /proc/cgroups
cgroups挂载查看
/sys/fs/cgroup# mount | grep cgroup
查看一个进程上的 cgroup 限制
cat /proc/$$/cgroup
$$ 表示上一个进程。
2. pidstat
pidstat 是 sysstat 的一个命令,用于监控全部或指定进程的 CPU、内存、线程、设备、IO 等系统资源的占用情况,在配合 cgroups 使用中起到监控数据的作用。pidstat 第一次采样显示自系统启动开始的各项统计信息,后续采样将显示自上次运行命令后的统计信息,用户可以通过指定统计的次数和时间来获得所需的统计信息。
安装:
pidstat 并不会内置在 Linux 各版本的系统里,需要手动安装
apt install sysstat -y #Ubuntu
yum install sysstat -y #CentOS
语法:
pidstat [option] [time interval] [times]
选项 | 含义 |
---|---|
-u | 显示各进程的 CPU 使用统计(默认参数)。 |
-r | 显示各进程的内存使用统计。 |
-d | 显示各进程的 IO 使用情况。 |
-p | 指定 pid ,ALL 表示所有进程。 |
-C | 指定进程名或进程 pid。 |
-l(←这是 l l l ) | 显示命令名和所有参数。 |
3. stress
stress 是 Linux 的一个压力测试工具,可以对 CPU、Memory、IO、磁盘进行压力测试。
安装:
stress 在各版本的 Linux 并不是内置的,需要手动安装
apt install stress -y #Ubuntu
yum install stress -y #CentOS
语法:
stress [option [arg]]
-
-c, --cpu N: 产生 N 个进程,每个进程都循环调用 sqrt 函数产生 CPU 压力。
-
-i, --io N: 产生 N 个进程,每个进程循环调用
sync()
将内存缓冲区内容写到磁盘上,产生 IO 压力。通过系统调用
sync()
刷新内存缓冲区数据到磁盘中,以确保同步。如果缓冲区内数据较少,写到磁盘中的数据页较少,不会产生 IO 压力。在 SSD 磁盘环境中尤为明显,很可能 iowait 总是 0,却因为大量调用sync()
,导致系统 CPU 使用率 sys 升高。 -
-m, --vm N:产生 N 个进程,每个循环调用
mallc()/free()
函数分配和释放内存。- –vm-bytes B: 指定分配内存的大小。
- –vm-keep: 一直占用内存,区别在于不进行释放和重新分配(默认是不断释放并重新分配内存)。
-
-d, --hdd N: 产生 N 个进程,每个不断执行
write()
和unlink()
,即创建文件、写入内容、删除文件操作。- –hdd-bytes B: 指定文件大小。
-
-t, --timeout N: 在 N 秒后结束程序。
-
-q, --quiet: 程序在运行的过程中不输出信息。
4. 使用 cgroups 对内存进行控制
cgroups 有两个版本,cgroup 和 cgroup2 。使用 CentOS 系统一般是 cgroup 而 Ubuntu 为 cgroup2(默认)。这两个版本的文件内容还是有较大区别的。由于我的系统是默认使用 cgroup2 ,以下给出的 cgroup 版本方法也就不提供图片了。
4.1 cgroup版本
在 cgroup 的内存控制目录 /sys/fs/cgroup/memory
中创建的文件夹,系统会帮我们生成一切内存控制相关的文件,我们只需要在这些文件中进行添加或修改,就能达到进程资源控制的效果。
第一步,创建一个目录:
mkdir test_memory
打开该目录下的 memory.limit_in_bytes
文件,可以看到当前内存的限制,默认应该是 -1
表示不限制:
cat test_memory/memory.limit_in_bytes
第二步,写入限制 20MB 到该文件中:
echo "20971520" >test_memory/memory.limit_in_bytes
第三步,使用 stress 启动一个进程,使其消耗 50MB 内存:
stress -m 1 --vm-bytes 50M
第四步,将该进程的 pid 写入到 test_memory/tasks
的文件中,可以看到进程因为内存资源不足而异常中止(可以看下面的 cgroup2 观察效果)。
4.2 cgroup2版本
在 cgroup2 版本中 memory 是统一管理的,没有/memory
这个目录。对内存限制的操作,在 /sys/fs/cgroup
下进行操作即可。
第一步,创建一个目录:
mkdir test_memory
可以看到系统自动生成了一堆控制相关的文件:
打开该目录下的 memory.max
文件,可以看到当前内存的限制:
cat ./test_memory/memory.max
默认是 max
表示不限制:
第二步,向写入限制 20MB 到该文件中:
echo "20M" > test_memory/memory.max
第三步,使用 stress 启动一个进程,使其消耗 50MB 内存:
stress -m 1 --vm-bytes 50M
使用 pidstat 查看启动的进程的 pid:
pidstat -r -C stress 1 10000
第四步,将将该进程的 pid 写入到 test_memory/cgroup.procs
的文件中:
echo "[pid]" > test_memory/cgroup.procs
可以观察到,在将该进程的 pid 添加到 cgroup.procs
文件的一瞬间,进程因为内存不足而异常终止:
5. 使用 cgroups 对内存进行控制
5.1 cgroup版本
在 cgroup 的 cpu 控制目录 /sys/fs/cgroup/cpu
中创建的文件夹,系统会帮我们生成一切 cpu 控制相关的文件,我们只需要在这些文件中进行添加或修改,就能达到进程资源控制的效果。
CPU 资源是通过 cfs_quota_us/cfs_period_us
决定的,cfs_period_us
的默认值是
100000
100000
100000 ,即对 CPU 资源的控制可以精确到
0.001
%
0.001\%
0.001% 。 而 cfs_quota_us
的默认值是 -1
,表示不限制。
第一步,创建文件夹:
mkdir /sys/fs/cgroup/cpu/test_cpu
第二步,设置 cfs_quota_us
的值设置为
30000
30000
30000 ,理论上限制 CPU 的使用率上限为
30
%
30\%
30% :
echo 30000 > test_cpu/cpu.cfs_quota_us
第三步,使用 stress 启动一个进程,使其 CPU 使用率为 100 % 100\% 100% :
stress -c 1
使用 pidstat 查看启动的进程的 pid:
pidstat -u -C stress 1 10000
第四步,将该进程的 pid 添加到 test_cpu/tasks
,可以观察到该进程的 CPU 使用率降到
30
%
30\%
30% :
echo [pid] > test_cpu/tasks
5.2 cgroup2版本
与内存控制一样,在 /sys/fs/cgroup
下创建目录即可,cgroup2 将两种控制放在同一个目录中管理了。
第一步,创建文件夹:
mkdir /sys/fs/cgroup/test_cpu
可以看到系统自动生成了一堆控制相关的文件:
打开该目录下的 memory.max
文件,可以看到当前内存的限制:
cat test_cpu/memory.max
默认是 max
表示不限制:
注意,在 cgroup2 中,CPU 使用率限制不再分两个文件,而是统一用 memory.max
进行设置,格式为 [quota] [period]
。
第二步,设置 memory.max
的值设置为 30000 1000000
,理论上限制 CPU 的使用率上限为
30
%
30\%
30% :
echo "30000 100000" > test_cpu/cpu.max
第三步,使用 stress 启动一个进程,使其 CPU 使用率为 100 % 100\% 100% :
stress -c 1
使用 pidstat 查看启动的进程的 pid:
pidstat -u -C stress 1 10000
第四步,将该进程的 pid 添加到 test_cpu/cgroup.procs
,可以观察到该进程的 CPU 使用率降到
30
%
30\%
30% :
echo [pid] > test_cpu/cgroup.procs