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

Linux control group笔记

Linux CGroup(Control Groups)是一个强大的内核功能,用于限制、记录和隔离进程组(process groups)使用的系统资源(如 CPU、内存、磁盘 I/O、网络等)。它通过将进程分组并对这些组进行资源分配和控制,来实现资源的精细化管理。

🔧 CGroup 核心概念

CGroup 主要围绕以下几个核心概念构建:

  • 子系统 (Subsystem):也称为控制器,是资源控制的具体模块。例如:
    • cpu:控制 CPU 访问。
    • memory:限制内存使用。
    • blkio:限制块设备 I/O。
    • cpuset:分配 CPU 和内存节点。
    • pids:限制进程数量。
  • 控制组 (CGroup):一组进程的集合。每个控制组都可以关联一个或多个子系统,并为这些子系统设置特定的资源限制参数。
  • 层级结构 (Hierarchy)`:控制组以树形结构组织。子控制组默认继承父控制组的属性,但也可自定义。
  • 任务 (Tasks):任务对应进程或线程。任务可以加入某个控制组,从而受到该控制组所有子系统限制规则的约束。

📊 CGroup 的版本

CGroup 主要有两个版本:v1v2。v2 旨在简化设计并统一资源配置,许多现代 Linux 发行版已默认使用 cgroup v2(检查 /sys/fs/cgroup/cgroup.controllers 是否存在)。两者在操作和功能上有些差异,建议新项目优先考虑 v2。

🛠️ CGroup 的管理与使用

管理 CGroup 主要有两种方式:

  1. 通过虚拟文件系统 (VFS) 手动操作:CGroup 通过一个虚拟文件系统(通常挂载在 /sys/fs/cgroup)暴露其接口。你可以通过创建目录、读写文件来创建控制组、设置参数和添加进程。

  2. 使用命令行工具:如 cgroup-tools 包(例如 cgcreate, cgset, cgexec)提供了更方便的命令行操作。
    cgcreate
    cgdelete
    lscgroup
    cgset
    cgget

    systemd-cgls
    systemd-cgtop

常用命令示例

以下是一些使用 cgroup-tools 的常见命令示例(部分命令在 v2 中可能有所不同或需调整):

功能命令示例说明
创建控制组sudo cgcreate -g cpu,memory:mygroup创建名为 mygroup 的控制组,并关联 cpumemory 控制器。
设置 CPU 限制sudo cgset -r cpu.max='50000 100000' mygroup (v2)在 v2 中,设置 mygroup 在周期 100000us 内最多使用 50000us 的 CPU 时间(即 50% 的单核利用率)。
sudo cgset -r cpu.cfs_quota_us=50000 -r cpu.cfs_period_us=100000 mygroup (v1)在 v1 中实现同上限制。
设置内存限制sudo cgset -r memory.max=100M mygroup (v2)限制 mygroup 最大内存使用为 100MB。
sudo cgset -r memory.limit_in_bytes=100M mygroup (v1)v1 中的内存限制设置。
在 CGroup 中运行进程sudo cgexec -g cpu,memory:mygroup /path/to/commandmygroup 控制组中启动一个进程。
将现有进程加入 CGroupsudo cgclassify -g cpu,memory:mygroup 1234将 PID 为 1234 的进程加入到 mygroup 控制组。
`echo 1234sudo tee /sys/fs/cgroup/mygroup/cgroup.procs`
删除控制组sudo cgdelete mygroup删除名为 mygroup 的控制组。
直接操作文件系统示例

你也可以直接与 /sys/fs/cgroup 下的文件交互:

# 创建控制组 (v1 示例,在cpu控制器下创建mygroup)
sudo mkdir /sys/fs/cgroup/cpu/mygroup# 设置CPU限制 (v1)
echo 100000 | sudo tee /sys/fs/cgroup/cpu/mygroup/cpu.cfs_period_us
echo 50000 | sudo tee /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us # 限制50%# 将进程加入控制组
echo 1234 | sudo tee /sys/fs/cgroup/cpu/mygroup/cgroup.procs# 删除控制组
sudo rmdir /sys/fs/cgroup/cpu/mygroup

💻 C++ 中的 CGroup API 调用

CGroup 主要通过虚拟文件系统提供接口,因此 C++ 中操作 CGroup 本质上就是对文件系统进行读写操作。你可以使用标准的 C++ 文件操作库(如 <fstream>)或 Linux 系统调用(如 open, write, read)。

下面是一个简单的例子,演示如何使用 C++ 将当前进程添加到指定 CGroup(这里以 v2 的 cgroup.procs 为例):

#include <fstream>
#include <iostream>
#include <string>bool add_self_to_cgroup(const std::string& cgroup_path) {// 获取当前进程的 PIDpid_t pid = getpid();// 构建 cgroup.procs 文件的完整路径std::string procs_file_path = cgroup_path + "/cgroup.procs";// 以写入模式打开文件std::ofstream procs_file(procs_file_path);if (!procs_file.is_open()) {std::cerr << "Failed to open " << procs_file_path << std::endl;return false;}// 将 PID 写入文件procs_file << pid;if (procs_file.fail()) {std::cerr << "Failed to write PID to " << procs_file_path << std::endl;procs_file.close();return false;}procs_file.close();std::cout << "Successfully added PID " << pid << " to " << cgroup_path << std::endl;return true;
}int main() {// 假设你要加入的 CGroup 路径 (需要根据实际情况修改)std::string my_cgroup_path = "/sys/fs/cgroup/my_cgroup";if (add_self_to_cgroup(my_cgroup_path)) {// 进程现在已经在 CGroup 中了,后续的资源使用将受到限制// ... 在这里执行你的受限制任务 ...std::cout << "Process is now within the cgroup. Running restricted task..." << std::endl;// 模拟一些工作volatile int i = 0;while (i < 100000000) { i++; }} else {return 1;}return 0;
}

重要说明

  • 这段代码需要以 root 权限运行,因为通常只有 root 用户才能修改 CGroup 配置。
  • 代码中的 CGroup 路径 (my_cgroup_path) 需要根据你的系统实际情况和要使用的控制器进行修改。对于 cgroup v2,通常挂载在 /sys/fs/cgroup,而你需要在其下创建或使用已有的子目录。
  • 这只是一个简单的示例,演示如何添加进程。要设置资源限制(如 CPU、内存),你还需要在运行此程序前,手动使用 cgsetecho 到相应文件等方式,提前为这个 CGroup 配置好限制参数(例如设置 my_cgroup/cpu.max)。
  • 更复杂的操作(如创建 CGroup、设置各种参数)同样可以通过 C++ 代码读写其他 CGroup 接口文件来实现。逻辑类似:构建正确的文件路径,然后写入符合格式要求的字符串。

⚠️ 注意事项

  1. 权限问题:操作 CGroup 通常需要 root 权限
  2. 资源争抢:CGroup 的 CPU 限制(如 cpu.shares)只在进程竞争 CPU 时生效。如果一个进程空闲,它仍然可以使用所有可用 CPU;只有当多个进程需要 CPU 时,份额才起作用。
  3. 版本差异:务必注意你使用的 Linux 系统是 cgroup v1 还是 v2,因为它们的控制器、可调参数和文件系统结构可能不同。检查 /sys/fs/cgroup 的挂载情况。
  4. 系统服务管理:许多现代 Linux 发行版使用 systemd,它自身就使用 CGroup 来管理和隔离服务。你可以使用 systemctl set-property 命令来调整系统服务的资源限制。
  5. 错误处理:在实际的程序中,务必添加更健壮的错误处理。

💎 总结

CGroup 是 Linux 系统资源管理的利器。你可以通过:

  • 命令行工具(如 cgroup-tools)快速上手和管理。
  • 直接操作 /sys/fs/cgroup 下的文件来灵活控制。
  • C++ 程序中使用文件操作 API 来以编程方式与 CGroup 交互,实现进程的资源限制。

希望这些介绍和示例能帮助你更好地理解和使用 Linux CGroup。

⚙️ 查看进程所属的 CGroup

每个运行中的进程在 /proc/ 目录下都有对应的子目录,其中 cgroup 文件明确记录了该进程属于哪个 CGroup。

操作命令

cat /proc/<PID>/cgroup

输出示例

cat /proc/2467/cgroup
0::/system.slice/example.service

这里的 0::cgroup v2 中表示系统使用的唯一层级。/system.slice/example.service 则指明了该进程属于 example.service 这个 systemd 单元对应的 CGroup。

对于 cgroup v1,输出会更复杂,会显示进程在各个控制器(如 cpu, memory)层级中的路径:

12:memory:/user.slice/user-1000.slice
9:blkio:/user.slice/user-1000.slice
8:net_cls,net_prio:/
7:cpu,cpuacct:/user.slice/user-1000.slice
6:perf_event:/
5:freezer:/
4:cpuset:/
3:pids:/user.slice/user-1000.slice
2:devices:/user.slice/user-1000.slice
1:name=systemd:/user.slice/user-1000.slice/session-3.scope

每行由冒号分隔的三部分组成:

  • 第一列:层级ID(Hierarchy ID),对应 /proc/cgroups 中的信息。
  • 第二列:绑定的控制器(subsystem)列表,多个控制器用逗号隔开。
  • 第三列:该进程在此控制器层级中的路径(相对于CGroup挂载点的路径)。

若进程在容器中,此文件内容通常包含容器ID,例如:

0::/kubepods/besteffort/pod779e55c6-0467-4431-997f-25a71a8e8a8e/a9ccdd00512985cb6e6c8dff176cb3086a989e477200c9a1cfdf8749182fc1da

其中的长哈希串 a9ccdd00512985cb6e6c8dff176cb3086a989e477200c9a1cfdef8749182fc1da 通常就是容器ID。

通过进程名查找PID并查看CGroup

若不确定进程PID,可通过进程名先查找PID:

# 方法1:使用 ps 和 grep
ps -eo pid,comm | grep <进程名># 方法2:使用 pgrep(更简洁)
pgrep <进程名>

然后对找到的PID执行 cat /proc/<PID>/cgroup

也可写成一个简单的脚本:

#!/bin/bash
echo "查看进程 '$1' 的CGroup信息:"
for PID in $(pgrep "$1"); doecho "PID: $PID"cat /proc/$PID/cgroupecho "------"
done

保存为 find_cgroup.sh 后使用 bash find_cgroup.sh <进程名> 执行。

🔍 查看CGroup包含的进程

要查看一个CGroup包含了哪些进程,主要可通过查看CGroup文件系统中的应用文件来实现。

1. 通过 cgroup.procs 文件

在CGroup目录中,cgroup.procs 文件列出了该CGroup中的所有进程ID

操作命令

cat /sys/fs/cgroup/<控制器>/<CGroup路径>/cgroup.procs

例如

# 查看 system.slice/example.service 这个CGroup中的进程(假设在v2的unified层级下)
cat /sys/fs/cgroup/system.slice/example.service/cgroup.procs# 查看 v1 中 memory 控制器下 /user.slice/user-1000.slice 的进程
cat /sys/fs/cgroup/memory/user.slice/user-1000.slice/cgroup.procs

2. 通过 tasks 文件(主要见于cgroup v1)

在cgroup v1中,tasks 文件列出了该CGroup中的所有线程ID。一个进程的所有线程可能分布在不同的CGroup中。

操作命令

cat /sys/fs/cgroup/<控制器>/<CGroup路径>/tasks

注意:cgroup v2 中已移除了 tasks 文件,统一使用 cgroup.procs

3. 使用 cgclassify 命令

cgclassify 命令可用于将进程分类到指定CGroup,但结合 -g 参数也能用来查询特定进程所属的CGroup(此用法更侧重于查看进程所属CGroup,而非直接列出CGroup中的所有进程)。

sudo cgclassify -g <控制器>:<CGroup路径> <进程PID>

但更常用于查看进程所属CGroup信息的是 /proc/<PID>/cgroup 文件。

4. 使用 systemd-cgtop (systemd-cgls)

systemd-cgtop 命令可以像一个“顶级”命令一样,以交互方式按层级实时显示各CGroup的资源使用情况(如CPU、内存),同时也会显示出对应的CGroup名称。

操作命令

systemd-cgtop# output
Path                                                                 Tasks   %CPU   Memory  Input/s Output/s
/system.slice                                                          85    5.0   500.0M        -        -
/system.slice/example.service                                           1   80.0    10.0M        -        -
/user.slice                                                            50    2.0   200.0M        -        -ubuntu:/proc$ systemd-cgls
Control group /:
-.slice
├─user.slice 
│ └─user-1000.slice 
│   ├─user@1000.service 
│   │ ├─session.slice 
│   │ │ ├─org.gnome.SettingsDaemon.MediaKeys.service 
│   │ │ │ └─2614 /usr/libexec/gsd-media-keys
│   │ │ ├─org.gnome.SettingsDaemon.Smartcard.service 
│   │ │ │ └─2643 /usr/libexec/gsd-smartcard
│   │ │ ├─org.gnome.SettingsDaemon.Datetime.service 
│   │ │ │ └─2608 /usr/libexec/gsd-datetime
│   │ │ ├─xdg-document-portal.service 
│   │ │ │ ├─2048 /usr/libexec/xdg-document-portal
│   │ │ │ └─2059 fusermount3 -o rw,nosuid,nodev,fsname=portal,auto_unmount,subtype=portal>
│   │ │ ├─org.gnome.SettingsDaemon.Housekeeping.service 
│   │ │ │ └─2609 /usr/libexec/gsd-housekeeping
│   │ │ ├─org.gnome.Shell@x11.service 
│   │ │ │ ├─   2406 /usr/bin/gnome-shell
│   │ │ │ ├─   8869 cat
│   │ │ │ ├─   8870 cat
│   │ │ │ ├─  11977 /disk2/soft2/WindTerm_2.5.0_2nd/WindTerm
│   │ │ │ ├─  12025 /bin/bash -i -l
│   │ │ │ ├─  12040 /bin/bash -i -l
│   │ │ │ ├─  12047 /bin/bash -i -l
│   │ │ │ ├─  12120 /bin/bash -i -l
│   │ │ │ ├─  12176 docker start -i 106850ccf3bc
│   │ │ │ ├─  71449 gjs /usr/share/gnome-shell/extensions/ding@rastersoft.com/ding.js -E >
│   │ │ │ ├─ 434225 /bin/bash -i -l
│   │ │ │ ├─ 461638 /bin/bash -i -l
│   │ │ │ ├─ 479174 docker start -i aee853fd0881
│   │ │ │ ├─1767812 /bin/bash -i -l
│   │ │ │ ├─1767852 /bin/bash -i -l
│   │ │ │ ├─2658314 systemd-cgls
│   │ │ │ ├─2658315 pager
│   │ │ │ └─4055392 /bin/bash -i -l

这能帮你快速了解哪些CGroup正在消耗资源。

📊 快速对比:查看CGroup与进程归属的方法

下表总结了上述方法的主要用途和特点:

查询目标主要方法/命令关键文件或参数说明
进程所属的CGroupcat /proc/<PID>/cgroup/proc/<PID>/cgroup最直接的方法,同时适用于cgroup v1和v2。
cgclassify (查询)-g <控制器>:<CGroup路径> <PID>更常用于分类进程,查询信息不如/proc直观。
CGroup包含的进程cat /sys/fs/cgroup/.../cgroup.procscgroup.procs列出CGroup中的所有进程ID(v1和v2均适用)。
cat /sys/fs/cgroup/.../tasks (v1)tasks列出CGroup中的所有线程ID(主要用于cgroup v1)。
监控CGroup资源与进程归属systemd-cgtop-交互式实时监控各CGroup资源使用情况,会显示CGroup名称。

💎 实用技巧与注意事项

  1. 区分CGroup版本:你的系统可能使用 cgroup v1v2,两者在文件系统结构和一些文件上有差异(如v2移除了tasks文件)。检查 /sys/fs/cgroup 的挂载情况可以判断版本。
  2. 权限问题:读取 /proc/<PID>/cgroup 通常不需要特殊权限(只要你有权访问该进程)。但查看或操作 /sys/fs/cgroup/ 下的文件,尤其是修改,通常需要 root 权限。
  3. 容器环境:在容器环境中,/proc/<PID>/cgroup 文件的内容是识别进程属于哪个容器的重要依据,因为路径常包含容器ID。
  4. 使用 lscgroup 命令:有些发行版可能安装了 cgroup-tools 包,其中包含 lscgroup 命令,可用于列出所有存在的CGroup。

掌握这些方法,你就能轻松地在进程和CGroup之间进行双向查找了。


文章转载自:

http://KmCY7NAd.jLjwk.cn
http://LgmivgaG.jLjwk.cn
http://jyVQQSKL.jLjwk.cn
http://w0T4EUWn.jLjwk.cn
http://KWmLJRp2.jLjwk.cn
http://eq1ILV0O.jLjwk.cn
http://Zp3Hhp1e.jLjwk.cn
http://UpGyeWxz.jLjwk.cn
http://vwaNcdPz.jLjwk.cn
http://6O9Lb0ND.jLjwk.cn
http://Yv1EFhX1.jLjwk.cn
http://9xf8V0V4.jLjwk.cn
http://FGWBVU0Z.jLjwk.cn
http://BTJJ3Seh.jLjwk.cn
http://YjBSpA6p.jLjwk.cn
http://tgWh6tgw.jLjwk.cn
http://HbvRFUJA.jLjwk.cn
http://3C8omcXp.jLjwk.cn
http://2PGnZvXZ.jLjwk.cn
http://WXewIjPp.jLjwk.cn
http://nW45KzzI.jLjwk.cn
http://mVeBDDrT.jLjwk.cn
http://tWzKzpKh.jLjwk.cn
http://76NSylvj.jLjwk.cn
http://xNh4F8d7.jLjwk.cn
http://CZVkTdPH.jLjwk.cn
http://uAwDadE8.jLjwk.cn
http://i2s0KByT.jLjwk.cn
http://pc54V8li.jLjwk.cn
http://l7q2sa0t.jLjwk.cn
http://www.dtcms.com/a/372887.html

相关文章:

  • 【Nginx】性能优化与实战(上)
  • LangChain RetrievalQA
  • MybatisPlus开启多租户三步快速集成
  • 现代Web应用前后端架构设计与Python实战
  • YOLO介绍(1)
  • 【javaSE】String类
  • 9.渗透-.Linux基础命令(一)(有vi编辑器)
  • LeetCode - LCR 179. 查找总价格为目标值的两个商品
  • ArcGIS Pro 遇到严重的应用程序错误而无法启动
  • 轻松Linux-9.进程间通信
  • 20250908的学习笔记
  • Golang 与 gRPC
  • shareId 的产生与传递链路
  • Go语言实战案例-开发一个JSON格式校验工具
  • AI技术架构与GEO算法原理如何重塑搜索引擎可见性
  • 【AI测试前沿】谷歌Fuzzing安全测试Go语言指南
  • 佰力博检测与您探讨薄膜样品如何测介电常数?
  • jsBridge接入流程
  • TFS-2018《On the convergence of the sparse possibilistic c-means algorithm》
  • ArrayList中的源码解析
  • 详细解析SparkStreaming和Kafka集成的两种方式的区别和优劣
  • 大数据Spark(六十三):RDD-Resilient Distributed Dataset
  • 云原生TodoList Demo 项目,验证云原生核心特性
  • C语言爬虫开发:常见错误与优化方案
  • Linux 应急响应实操 Checklist
  • 【PCIe EP 设备入门学习专栏 -- 8.2.3 Local Bus Controller (LBC) 详细介绍】
  • 将基于 Oracle JDK 17 开发的 Spring Boot 3.2.12 项目迁移到 OpenJDK 17 环境
  • Vue的计算属性
  • Redis 非缓存核心场景及实例说明
  • 食品罐头(铝罐)表面缺陷数据集:8k+图像,4类,yolo标注