当前位置: 首页 > article >正文

【Linux】资源控制机制 — cgroups 详解

文章目录

  • 一、什么是 Cgroups(Control Groups)
  • 二、功能 原理
    • 2.1 功能
    • 2.2 主要子系统(Controller):
    • 2.3 Cgroups 的工作原理:
  • 三、基础相关知识
    • 3.1 pidstat
    • 3.2 stress
  • 四、实操
    • 4.1 cgroups 信息查看
    • 4.2 使用 cgroups 对内存进行控制
    • 4.3 使用 cgroups 对 CPU 进行控制


一、什么是 Cgroups(Control Groups)

Cgroups(控制组)是 Linux 内核提供的一项功能,旨在对一组进程进行资源分配、限制、优先级调整和监控

通过 Cgroups,系统管理员可以将进程组织成多个组,并对这些组的资源使用情况进行控制和管理。

Cgroups 允许用户对 CPU、内存、磁盘 I/O、网络带宽等资源进行细粒度的管理,能够限制、优先分配或监控这些资源,确保系统资源在多个进程或容器之间合理分配。


二、功能 原理

2.1 功能

  1. 资源限制

    • 可以限制进程组使用的 CPU 时间、内存磁盘 I/O 带宽等。例如,限制某些进程组使用不超过一定的 CPU 时间或者内存大小。
  2. 资源优先级分配

    • 可以为进程组设置不同的优先级,以确保某些关键进程获得更多的资源。例如,可以为高优先级的进程分配更多的 CPU 时间片,或限制低优先级进程的资源使用。
  3. 资源监控

    • 可以监控和跟踪 Cgroups 内的进程的资源使用情况,提供例如 CPU 使用率、内存消耗、I/O 活动等统计信息。
  4. 资源隔离

    • Cgroups 提供进程之间的资源隔离,确保一个进程组不会消耗过多的系统资源,从而影响到其他进程组的正常运行。
  5. 动态调整

    • 可以在运行时动态地调整 Cgroups 中进程的资源配额。例如,管理员可以在不重启系统的情况下修改进程组的资源限制。

2.2 主要子系统(Controller):

Cgroups 提供了多个“控制器”(controllers)来管理不同类型的资源。每个控制器负责管理某一类资源的使用。常见的 Cgroups 控制器包括:

  1. CPU(cpu、cpuacct)

    • 用于限制和跟踪进程组的 CPU 使用。可以限制一个进程组的 CPU 时间,或者为不同进程组分配不同的 CPU 时间比例。
    • cpu:限制 CPU 使用。
    • cpuacct:记录进程的 CPU 使用情况。
  2. 内存(memory)

    • 用于限制进程组的内存使用。可以设置内存的软限制(soft limit)和硬限制(hard limit),超过限制时会触发 OOM(Out Of Memory)杀手。
    • 该控制器可以确保每个进程组不会使用超过其分配的内存量,防止某些进程组耗尽整个系统的内存。
  3. 磁盘 I/O(blkio)

    • 用于限制和控制进程组的磁盘 I/O 带宽。可以限制某个进程组的磁盘读取和写入速度。
    • 例如,可以限制一个进程组每秒读取或写入的字节数,防止某个进程对磁盘的过度访问影响到其他进程的磁盘 I/O。
  4. 网络(net_cls、net_prio)

    • 用于管理和限制进程组的网络带宽使用。
    • net_cls:为进程组分配不同的网络类别,允许在网络中应用不同的 QoS(Quality of Service)策略。
    • net_prio:设置进程的网络优先级。
  5. 任务和进程数量限制(pids)

    • 用于限制进程组内的进程数量。例如,可以为某个进程组设置一个最大进程数,防止进程组创建过多的进程导致系统资源耗尽。
  6. CPU亲和性(cpuset)

    • 允许用户指定某个进程组运行在特定的 CPU 核心上,从而提高 CPU 使用效率并减少 CPU 上的上下文切换。
  7. 控制组的统一管理(cgroup)

    • 用于管理所有的 Cgroup 设置,并提供统一的接口来创建、销毁、查询 Cgroups。

2.3 Cgroups 的工作原理:

  1. 创建控制组:在 Linux 中,Cgroups 是通过在文件系统(如 /sys/fs/cgroup/)中创建目录来表示的,每个目录对应一个控制组。每个进程通过将其 PID 加入到某个 Cgroup 目录下,来加入该 Cgroup。

  2. 资源限制:每个 Cgroup 目录下都会有一些文件,这些文件对应于不同资源的限制。管理员可以通过写入这些文件来控制资源。例如,通过 memory.limit_in_bytes 文件可以设置内存的限制,cpu.cfs_quota_us 可以限制 CPU 使用的时间。

  3. 进程加入 Cgroup:可以通过将进程的 PID 写入到 Cgroup 目录的 tasks 文件中,将该进程加入到相应的 Cgroup 中。之后,进程的资源使用将受到该 Cgroup 配置的限制。


三、基础相关知识

3.1 pidstat

  • 概述:

pidstatsysstat 的一个命令,用于监控全部或指定进程的 CPU、内存、线程、设备IO 等系统资源的占用情况

pidstat 第一次采样显示自系统启动开始的各项统计信息,后续采样显示自上次运行命令后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。

  • 语法:

    pidstat [ 选项 ] [ <时间间隔> ] [ <次数> ]
    
  • 参数:

    • -u:默认参数,显示各进程的 CPU 使用统计
    • -r:显示各进程的内存使用统计
    • -d:显示各进程的 IO 使用情况
    • -p:指定进程号,ALL 表示所有进程
    • -C:指定命令
    • -l:显示命令名和所有参数

3.2 stress

stress 是 Linux 的一个压力测试工具,可以对 CPU、 Memory、 IO、磁盘进行压力测试。

  • 语法:
    stress [OPTION [ARG]]
    
  • 参数:
选项描述
-c, --cpu N产生 N 个进程,每个进程都循环调用 sqrt 函数产生 CPU 压力。
-i, --io N产生 N 个进程,每个进程循环调用 sync 将内存缓冲区内容写到磁盘上,产生 IO 压力。
--vm-bytes B指定分配内存的大小。
-m, --vm N产生 N 个进程,每个进程循环调用 malloc/free 函数分配和释放内存。
--vm-keep一直占用内存,区别于不断的释放和重新分配内存(默认是不断释放并重新分配内存)。
-d, --hdd N产生 N 个不断执行 writeunlink 函数的进程(创建文件,写入内容,删除文件)。
--hdd-bytes B指定文件大小。
-t, --timeout N在 N 秒后结束程序。
-q, --quiet程序在运行的过程中不输出信息。

四、实操

4.1 cgroups 信息查看

  1. cgroups 版本查看:
wqy@wqy-virtual-machine:~$ cat /proc/filesystems | grep cgroup
nodev	cgroup
nodev	cgroup2
  1. cgroups 子系统查看:
wqy@wqy-virtual-machine:~$ cat /proc/cgroups
#subsys_name	hierarchy	num_cgroups	enabled
cpuset	0	162	1
cpu	0	162	1
cpuacct	0	162	1
blkio	0	162	1
memory	0	162	1
devices	0	162	1
freezer	0	162	1
net_cls	0	162	1
perf_event	0	162	1
net_prio	0	162	1
hugetlb	0	162	1
pids	0	162	1
rdma	0	162	1
misc	0	162	1
  1. cgroups 挂载信息查看:

执行指令后可以看到:默认存储位置为 /sys/fs/cgroup

wqy@wqy-virtual-machine:~$ mount | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
  1. 查看一个进程上的 cgroup 限制

以当前的shell进程为例,执行指令进行查看:

wqy@wqy-virtual-machine:~$ cat /proc/$$/cgroup
0::/user.slice/user-1000.slice/user@1000.service/app.slice/app-org.gnome.Terminal.slice/vte-spawn-02da5c30-f3a4-4bdf-94e1-27362546d1a7.scope

4.2 使用 cgroups 对内存进行控制

1. 创建内存的 cgroup

首先,我们进入到 cgroup 的内存控制目录 /sys/fs/cgroup/memory,然后创建一个新的目录 test_memory

wqy@virtual-machine:/sys/fs/cgroup/memory$ mkdir test_memory
wqy@virtual-machine:/sys/fs/cgroup/memory$ ll
total 0
dr-xr-xr-x 7 root root 0 Mar 10 14:13 ./
drwxr-xr-x 15 root root 380 Mar 10 14:13 ../
-rw-r--r-- 1 root root 0 Mar 12 14:13 cgroup.clone_children
--w--w--w- 1 root root 0 Mar 12 14:13 cgroup.event_control
-rw-r--r-- 1 root root 0 Mar 12 14:13 cgroup.procs
-r--r--r-- 1 root root 0 Mar 12 14:13 cgroup.sane_behavior
drwxr-xr-x 2 root root 0 Mar 12 14:13 docker/
drwxr-xr-x 2 root root 0 Mar 12 14:13 init.scope/
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.failcnt
--w------- 1 root root 0 Mar 12 14:13 memory.force_empty
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.tcp.failcnt-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:13 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Mar 12 14:13 memory.numa_stat
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.oom_control
---------- 1 root root 0 Mar 12 14:13 memory.pressure_level
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:13 memory.stat
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.swappiness
-r--r--r-- 1 root root 0 Mar 12 14:13 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:13 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Mar 12 14:13 notify_on_release
-rw-r--r-- 1 root root 0 Mar 12 14:13 release_agent
drwxr-xr-x 95 root root 0 Mar 12 13:22 system.slice/
-rw-r--r-- 1 root root 0 Mar 12 14:13 tasks
drwxr-xr-x 2 root root 0 Mar 12 14:14 test_memory/
drwxr-xr-x 3 root root 0 Mar 12 13:58 user.slice/

2. 查看 test_memory 目录中的文件

test_memory 目录下,内存限制相关的配置文件已经自动创建。

wqy@virtual-machine:/sys/fs/cgroup/memory/test_memory$ ll
total 0
drwxr-xr-x 2 root root 0 Mar 12 14:14 ./
dr-xr-xr-x 7 root root 0 Mar 10 14:13 ../
-rw-r--r-- 1 root root 0 Mar 12 14:14 cgroup.clone_children
--w--w--w- 1 root root 0 Mar 12 14:14 cgroup.event_control
-rw-r--r-- 1 root root 0 Mar 12 14:14 cgroup.procs
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.failcnt
--w------- 1 root root 0 Mar 12 14:14 memory.force_empty
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.numa_stat
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.oom_control
---------- 1 root root 0 Mar 12 14:14 memory.pressure_level
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.stat
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.swappiness
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.usage_in_bytes

3. 配置 cgroup 的策略为最大使用 20MB 内存

接下来,将 memory.limit_in_bytes 文件的内容设置为 20M(即 20971520 字节)。

wqy@virtual-machine:/sys/fs/cgroup/memory$ expr 20 \* 1024 \* 1024
20971520
wqy@virtual-machine:/sys/fs/cgroup/memory$ cat test_memory/memory.limit_in_bytes
9223372036854771712
wqy@virtual-machine:/sys/fs/cgroup/memory$ echo "20971520" > test_memory/memory.limit_in_bytes
wqy@virtual-machine:/sys/fs/cgroup/memory$ cat test_memory/memory.limit_in_bytes
20971520

4. 启动一个消耗内存的进程

我们启动一个内存消耗较大的进程,每个进程占用 50MB 内存。

wqy@virtual-machine:/sys/fs/cgroup$ stress -m 1 --vm-bytes 50M
stress: info: [62106] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd

5. 使用 pidstat 查看进程状态

打开一个新的 Shell 窗口 B,并使用 pidstat 来查看进程的内存使用情况。红色部分显示的是进程的 PID。

wqy@virtual-machine:/sys/fs/cgroup/memory# pidstat -r -C stress -p ALL 1 10000
Linux 5.4.0-100-generic (139-159-150-152) 03/12/2023
_x86_64_ (1 CPU)
02:47:01 PM UID       PID    minflt/s  majflt/s     VSZ     RSS   %MEM   Command
02:47:02 PM   0     62517        0.00      0.00    3856     988   0.05   stress
02:47:02 PM   0     62518   476597.03      0.00   55060   15156   0.75   stress
02:47:02 PM UID       PID    minflt/s  majflt/s     VSZ     RSS   %MEM   Command
02:47:03 PM   0     62517        0.00      0.00    3856     988   0.05   stress
02:47:03 PM   0     62518   483459.00      0.00   55060    3540   0.17   stress
02:47:03 PM UID       PID    minflt/s  majflt/s     VSZ     RSS   %MEM   Command
02:47:04 PM   0     62517        0.00      0.00    3856     988   0.05   stress
02:47:04 PM   0     62518   489336.00      0.00   55060   15156   0.75   stress
  1. 打开一个新的 shell C 窗口,将进程 id 移动到我们的 cgroup 策略
cd /sys/fs/cgroup/memory
echo 62518 >> test_memory/tasks
  1. 进程无法申请到足够的内存,随后进程退出。

4.3 使用 cgroups 对 CPU 进行控制

1. 创建内存的 cgroup
很简单,我们进入到 cgroup 的内存控制目录 /sys/fs/cgroup/cpu,创建目录 test_cpu。可以看到系统会自动为我们创建 cgroup 的 CPU 策略。

wqy@virtual-machine:/sys/fs/cgroup/cpu$ cd /sys/fs/cgroup/cpu  
wqy@virtual-machine:/sys/fs/cgroup/cpu$ mkdir test_cpu  
wqy@virtual-machine:/sys/fs/cgroup/cpu$ ll test_cpu  
total 0  
drwxr-xr-x 2 root root 0 Mar 12 14:54 ./  
dr-xr-xr-x 9 root root 0 Mar 10 14:13 ../  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cgroup.clone_children  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cgroup.procs  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.stat  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage_all  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage_percpu  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage_percpu_sys  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage_percpu_user  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage_sys  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpuacct.usage_user  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cpu.cfs_period_us  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cpu.cfs_quota_us  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cpu.shares  
-r--r--r-- 1 root root 0 Mar 12 14:54 cpu.stat  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cpu.uclamp.max  
-rw-r--r-- 1 root root 0 Mar 12 14:54 cpu.uclamp.min  
-rw-r--r-- 1 root root 0 Mar 12 14:54 notify_on_release  
-rw-r--r-- 1 root root 0 Mar 12 14:54 tasks  

2. 使用 stress 模拟一个任务,CPU 使用率为 100%

打开新的 Shell 窗口(B 窗口),运行以下命令:

wqy@virtual-machine:/sys/fs/cgroup$ stress -c 1  
stress: info: [62576] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd  

3. 监控 CPU 使用率

可以看到 CPU 的使用率为 100%:

wqy@virtual-machine:/sys/fs/cgroup/memory$ pidstat -u -C stress -p ALL 1 10000  
Linux 5.4.0-100-generic (wqy@virtual-machine) 03/12/2023 _x86_64_ (1 CPU)  
02:59:38 PM UID PID %usr %system %guest %wait %CPU CPU Command  
02:59:39 PM 0 62576 0.00 0.00 0.00 0.00 0.00 0 stress  
02:59:39 PM 0 62577 99.01 0.00 0.00 0.99 99.01 0 stress  

4. 设置 cgroup 的 CPU 使用率为 30%

打开新的 Shell 窗口(C 窗口),通过以下计算和命令限制 CPU 使用率:

公式cfs_quota_us / cfs_period_us

  1. cfs_period_us 表示一个 CPU 带宽,默认值为 100000(100ms)。
  2. cfs_quota_us 表示 Cgroup 可以使用的 CPU 带宽,设置为 30000,即限制 CPU 使用率为 30%。
wqy@virtual-machine:/sys/fs/cgroup/cpu$ cd /sys/fs/cgroup/cpu  
wqy@virtual-machine:/sys/fs/cgroup/cpu$ echo 30000 > test_cpu/cpu.cfs_quota_us  

5. 将进程 PID 添加到任务列表

获取任务 PID 为 62577,将其加入 test_cpu/tasks 进行控制:

wqy@virtual-machine:/sys/fs/cgroup/cpu$ echo 62577 > test_cpu/tasks  

6. 观察 CPU 使用率变化

在 B 窗口中可以看到,监控的 CPU 使用率从 100% 降低到 30%。


http://www.kler.cn/a/449418.html

相关文章:

  • # 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
  • 完整微服务设计 功能实现
  • JVM系列(十三) -常用调优工具介绍
  • 《计算机组成及汇编语言原理》阅读笔记:p48-p81
  • 练14:DFS基础
  • vscode 快速切换cangjie版本
  • Cesium材质——Material
  • 完成第一个 Vue3.2 项目后,这是我的技术总结
  • SSM-期末项目 - 基于SSM的宠物信息管理系统
  • 文本模式下成功。ubuntu P104成功。
  • 【系统架构设计师】真题论文: 论软件测试中缺陷管理及其应用(包括解题思路和素材)
  • Linux快速入门-Linux文件系统管理
  • 人工智能ACA(五)--深度学习基础
  • 深入理解构造函数:C++ 编程中的基石
  • C#中var关键字
  • 【MySQL篇】聚合查询,联合查询
  • 南开大学师唯教授团队:配位聚合物和金属-有机框架在电池中的应用
  • 从零开始C++棋牌游戏开发之第二篇:初识 C++ 游戏开发的基本架构
  • 基础8:可调用对象类型
  • Trim_Galore_User_Guide
  • 【AI日记】24.12.23 kaggle 比赛 2-11
  • Slate文档编辑器-TS类型扩展与节点类型检查
  • 详细解读sedex验厂
  • 【微信小程序】1|底部图标 | 我的咖啡店-综合实训
  • 搭建Elastic search群集
  • 利用Matlab绘制心性函数