本文将介绍cgroups
的组成和工作原理,通过示例演示 cgroups 的功能。 Cgroup(Control Groups)
是 Linux 内核提供的一种可以限制
、统计
、隔离进程组(process groups)
所使用物理资源(CPU、memory、disk I/O、network等)的机制。
介绍
cgroups
是linux提供的一种根据特定的限制,将一组任务和子任务(包括未来的)以层级组的形式进行聚合、隔离的机制。可以对一组进程以及将来的子进程进行资源的限制、统计和控制,能有效的防止进程间的资源强制。Cgroups 为 Linux 系统资源管理提供了统一的矿建,是 LXC 和 Docker 等容器技术实现资源管理的手段。
Cgroups 的主要概念
Task(任务)
:Linux 内核不区分进程和线程,这里的 task 表示一个进程或线程,在内核中的表现为 struct task_struct
control group(cgroup、控制组)
:按照一定规则划分的任务组,由一个或多个子系统(subsystem)组成,一个任务只能属于一个 cgroupsubsystem(子系统)
:具体的资源控制器,Ubuntu 20.04 中所有的子系统如下:
$ lssubsys --all
cpuset # 为进程分配单独的cpu/mem节点,如将 cgroup 中的进程绑定到指定的 CPU 或 NUMA 节点
cpu,cpuacct # CPU 时间片分配、资源报告
blkio # 块设备 io 相关限制
memory # 内存相关限制
devices # 硬件设备访问限制
freezer # 挂起和恢复 cgroup 中的所有进程
net_cls,net_prio # net_cls 标记进程的网络数据包,并进行控制。net_prio 动态配置进程每个网络接口的流量优先级
perf_event # perf 时间,可以使用 perf 工具监控 cgroup
hugetlb # 限制大页内存的使用量
pids # 限制进程数量
rdma # The RDMA controller permits limiting the use of RDMA/IB-specific resources per cgroup
misc
也可以通过如下工具获取:
$ cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset 4 22 1
cpu 8 140 1
cpuacct 8 140 1
blkio 9 140 1
memory 13 202 1
devices 10 140 1
freezer 7 22 1
net_cls 6 22 1
perf_event 3 22 1
net_prio 6 22 1
hugetlb 12 22 1
pids 2 151 1
rdma 5 1 1
misc 11 1 1
Hierarchy(层级)
:cgroup 以树的形式组织,每一个树称为一个层级,每个层级通过绑定对应的 cgroup 进行资源控制。层级中的 cgroup 由零个或多个子节点组成,子节点继承父节点的子系统。一个系统可以有多个层级。
Cgroups 的功能
- 资源限制:对 task 的资源总量进行限制,包括:memory、cpu、block io。如限定内存后,一旦超过就触发 OOM 事件
- 优先分配:通过 CPU 时间片(cpuset)等分配控制 task 的优先级
- 资源统计:统计系统资源的使用量,如 CPU 占用时长、内存占用量等
- 任务控制:对 task 挂起和恢复,freezer
管理工具
apt install cgroup-tools
示例
本示例展示如何使用 Cgroup 限制资源
memory 限制
# 进入目录
root@xiexianbin-cn:~# cd /sys/fs/cgroup/memory/
# 创建 demo 文件夹,即创建了一个 cgroup,删除该目录即删除刚创建的 cgroup
root@xiexianbin-cn:/sys/fs/cgroup/memory# mkdir demo
# 进入 demo 目录,列出该目录下自动创建的文件
root@xiexianbin-cn:/sys/fs/cgroup/memory# cd demo/
root@xiexianbin-cn:/sys/fs/cgroup/memory/demo# ll
total 0
drwxr-xr-x 2 root root 0 Feb 12 07:30 ./
dr-xr-xr-x 7 root root 0 Feb 10 10:20 ../
-rw-r--r-- 1 root root 0 Feb 12 07:30 cgroup.clone_children
--w--w--w- 1 root root 0 Feb 12 07:30 cgroup.event_control
-rw-r--r-- 1 root root 0 Feb 12 07:30 cgroup.procs
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.failcnt # 显示内存(进程内存+页面缓存)达到限制值的次数
--w------- 1 root root 0 Feb 12 07:30 memory.force_empty # 强制释放该分组的内存
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.limit_in_bytes # 设置/显示当前内存(进程内存+页面缓存)的限制值
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.max_usage_in_bytes # 显示内存(进程内存+页面缓存)+交换区使用量的最大值
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.memsw.failcnt # 显示内存(进程内存+页面缓存)+交换区到达限制值的次数
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.memsw.limit_in_bytes # 显示当前内存(进程内存+页面缓存)+交换区使用量的限制值
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.memsw.max_usage_in_bytes # 显示内存(进程内存+页面缓存)使用量的最大值
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.memsw.usage_in_bytes # 显示当前内存(进程内存+页面缓存)+交换区使用量的限制值
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.numa_stat
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.oom_control
---------- 1 root root 0 Feb 12 07:30 memory.pressure_level
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.stat # 输出统计信息
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.swappiness # 设置/显示针对分组的swappiness值
-r--r--r-- 1 root root 0 Feb 12 07:30 memory.usage_in_bytes # 显示当前内存(进程内存+页面缓存)的使用情况
-rw-r--r-- 1 root root 0 Feb 12 07:30 memory.use_hierarchy # 设置/显示层次结构的使用情况
-rw-r--r-- 1 root root 0 Feb 12 07:30 notify_on_release
-rw-r--r-- 1 root root 0 Feb 12 07:30 tasks # 设置/显示进程信息
root@xiexianbin-cn:/sys/fs/cgroup/memory/demo#
root@xiexianbin-cn:/sys/fs/cgroup/memory/demo# echo 102400 > memory.limit_in_bytes
root@xiexianbin-cn:/sys/fs/cgroup/memory/demo# cat memory.limit_in_bytes
102400
root@xiexianbin-cn:/sys/fs/cgroup/memory/demo# echo $$ > tasks # $$ 为当前进程的ID
/var/log/kern.log:Feb 12 07:45:42 k8s-master kernel: [488591.672012] Memory cgroup out of memory: Killed process 2757489 (bash) total-vm:20916kB, anon-rss:8616kB, file-rss:3756kB, shmem-rss:0kB, UID:0 pgtables:76kB oom_score_adj:0
CPU 限制
root@xiexianbin-cn:~# cd /sys/fs/cgroup/cpu
# 新建 demo cpu cgroup
root@xiexianbin-cn:/sys/fs/cgroup/cpu# mkdir demo
root@xiexianbin-cn:/sys/fs/cgroup/cpu# cd demo/
root@xiexianbin-cn:/sys/fs/cgroup/cpu/demo# ll
total 0
drwxr-xr-x 2 root root 0 Feb 12 07:51 ./
dr-xr-xr-x 7 root root 0 Feb 10 10:20 ../
-rw-r--r-- 1 root root 0 Feb 12 07:51 cgroup.clone_children
-rw-r--r-- 1 root root 0 Feb 12 07:51 cgroup.procs
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.stat
-rw-r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage_all
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Feb 12 07:51 cpuacct.usage_user
-rw-r--r-- 1 root root 0 Feb 12 07:51 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Feb 12 07:51 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Feb 12 07:51 cpu.shares
-r--r--r-- 1 root root 0 Feb 12 07:51 cpu.stat
-rw-r--r-- 1 root root 0 Feb 12 07:51 cpu.uclamp.max
-rw-r--r-- 1 root root 0 Feb 12 07:51 cpu.uclamp.min
-rw-r--r-- 1 root root 0 Feb 12 07:51 notify_on_release
-rw-r--r-- 1 root root 0 Feb 12 07:51 tasks
# 50000 相当于 cpu.cfs_period_us(100000) 微秒的 50%
root@xiexianbin-cn:/sys/fs/cgroup/cpu/demo# echo 50000 > cpu.cfs_quota_us
root@xiexianbin-cn:/sys/fs/cgroup/cpu/demo# echo $$ > tasks
root@xiexianbin-cn:~# cat /tmp/cpu.sh
x=0
while [ True ]; do
x=$x+1
done
root@xiexianbin-cn:~# bash /tmp/cpu.sh &&
root@xiexianbin-cn:~# top -p $$
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2752743 root 20 0 13456 4052 3124 R 50.2 0.1 0:33.11 bash
CPU 使用率大约为 50% 左右