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://www.pswp.cn/news/921729.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921729.shtml
英文地址,请注明出处:http://en.pswp.cn/news/921729.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小迪Web自用笔记30

Node.js原生态的js运行在前端。Node.js&#xff1a;他与原生态JS最大的不同&#xff0c;就是前端只能看到输出的代码&#xff0c;而看不到jS文件req接收&#xff0c;res回显dirname获取绝对路径提交表单 &#xff1a;“Post路由” 到底是什么。这是一个非常核心的Web开发概念。…

并发编程的守护者:信号量与日志策略模式解析

一、信号量 关于信号量的介绍在深入Linux内核&#xff1a;IPC资源管理揭秘 这篇文章当中已经做了初步的介绍了&#xff0c;相信大家对于信号量已经有了初步的认知了。 今天&#xff0c;我们就来探讨如何实现信号量。 1. 信号量的接口 //初始化信号量 //成功了&#xff0c;返…

conda 创建环境嵌套报错

使用conda create --prefix /path可以成功创建&#xff0c;有可能时默认路径冲突导致的 conda config --show 发现&#xff1a; envs_dirs: /root/autodl-tmp/miniconda3/envs/envs_test/path/root/autodl-tmp/miniconda3/envs/root/.conda/envs 未显式指定环境路径&#xf…

低代码核心原理总结

Web 低代码平台核心原理深度解析 1. 架构总览 Web低代码平台的核心架构包含四个关键层次&#xff1a; class LowCodePlatform {constructor() {this.visualEditor new VisualEditor(); // 可视化编辑器this.metaDataEngine new MetaDataEngine(); // 元数据引擎this.code…

操作系统研发工作心得体会 - 于复杂性中构建秩序

在操作系统&#xff08;OS&#xff09;研发这片要求极致严谨与创新的工程深海中航行数载&#xff0c;我的角色从一个纯粹的技术专家&#xff0c;逐渐演变为一个需要兼顾技术深度、系统广度与团队效能的复合型角色。这段旅程&#xff0c;让我深刻体会到&#xff0c;构建一个成功…

Excel 表格 - Excel 减少干扰、专注于内容的查看方式

Excel 减少干扰、专注于内容的查看方式 1、隐藏元素 点击 【视图】 -> 取消勾选 【网格线】 -> 取消勾选 【编辑栏】 -> 取消勾选 【标题】2、全屏显示 点击 【功能区显示选项】&#xff08;工具栏右下角小箭头&#xff09; -> 点击 【全屏模式】

C# Web API 前端传入参数时间为Utc

Web API 前端传入参数时间为Utc&#xff08;时间相差8个小时&#xff09;1.在Program.csbuilder.Services.AddControllers().AddJsonOptions(options > {// 序列化时将时间转换为本地时间&#xff08;北京时间&#xff09;options.JsonSerializerOptions.Converters.Add(new…

AI Agent开发入门:Semantic Kernel构建智能邮件助手

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;AI Agent——下一代人机交互范式 在人工智能技术…

WebAssembly:开启高性能 Web 应用的新篇章

在互联网技术飞速发展的浪潮中&#xff0c;Web应用的性能一直是一个重要的优化目标。传统的JavaScript虽然灵活便捷&#xff0c;但在处理CPU密集型任务时&#xff0c;其性能瓶颈日益凸显&#xff0c;限制了Web应用在游戏、音视频编辑、科学计算、图像处理等高性能领域的深入发展…

001-003 产品经理-ML应用构建-ML应用范围

001-003 产品经理-ML应用构建-ML应用范围 时间&#xff1a;2025年09月08日14:48:01 备注&#xff1a;笔记回顾和复习&#xff0c;仅用于分享而非商用&#xff0c;引用内容若侵权请联系并删除。 文章目录001-003 产品经理-ML应用构建-ML应用范围导引 学习法则1 内容索引 产品经…

软件测试错题笔记

1.capitalize()表示将字符串第一个字符转换为大写 2.pop()方法&#xff1a;指定一个键&#xff08;key&#xff09;作为参数来删除并返回对应的值&#xff0c;不传入任何参数报错。 3.测试方法&#xff1a;黑盒测试&#xff08;等价类划分法、边界值分析、因果图分析&#xf…

【一文分享】安全数据交换系统是什么?哪款产品性价比高?

随着数据价值的提升&#xff0c;其流动过程中的安全风险也与日俱增。内部核心数据泄露、外部攻击、不合规传输导致的合规风险……这些问题如同悬在企业头上的“达摩克利斯之剑”。正是在这样的背景下&#xff0c;安全数据交换系统 应运而生&#xff0c;成为了保障数据安全流动的…

postgresql9.2.4 离线安装

1、创建用户[rootvkeep ~]# groupadd postgres [rootvkeep ~]# useradd -g postgres postgres -m -s /bin/bash [rootvkeep ~]# echo "Database123" | passwd --stdin postgres2、安装依赖包[rootvkeep ~]# yum install gcc gcc-c zlib-devel readline readline-deve…

【C++设计模式】第三篇:观察者模式(别名:发布-订阅模式、模型-视图模式、源-监听器模式)

C设计模式系列文章目录 【C设计模式】第一篇 C单例模式–懒汉与饿汉以及线程安全 【C设计模式】第二篇&#xff1a;策略模式&#xff08;Strategy&#xff09;–从基本介绍&#xff0c;内部原理、应用场景、使用方法&#xff0c;常见问题和解决方案进行深度解析 【C设计模式】…

运作管理学习笔记5-生产和服务设施的选址

运作管理-北京交通大学5.1.设施选址概述 设施选址是一个战略性的决策&#xff0c;做这个决策的时候会投入比较多的资源&#xff0c;而且未来去改变选址的成本和代价也比较大。 5.1.1.设施选址的重要性 设施选址影响企业经营情况 设施选址对设施布局以及投产后的生产经营费用、产…

JUnit 详解

一、JUnit 简介&#xff1a;什么是 JUnit&#xff1f;为什么要用它&#xff1f;1.1 核心定义JUnit 是一个开源的、基于 Java 语言的单元测试框架&#xff0c;最初由 Erich Gamma (GoF 设计模式作者之一) 和 Kent Beck (极限编程创始人) 在 1997 年共同开发。作为 xUnit 测试框架…

数据结构造神计划第三天---数据类型

&#x1f525;个人主页&#xff1a;寻星探路 &#x1f3ac;作者简介&#xff1a;Java研发方向学习者 &#x1f4d6;个人专栏&#xff1a;《从青铜到王者&#xff0c;就差这讲数据结构&#xff01;&#xff01;&#xff01;》、 《JAVA&#xff08;SE&#xff09;----如此简单&a…

AI API Tester体验:API测试工具如何高效生成接口测试用例、覆盖异常场景?

前阵子帮后端测试支付接口时&#xff0c;我算是彻底明白 “API 测试能磨掉半条命”—— 明明接口文档里写了十几种参数组合&#xff0c;手动写测试用例时要么漏了 “签名过期” 的场景&#xff0c;要么忘了校验 “金额超过限额” 的返回值&#xff0c;测到半夜还被开发吐槽 “你…

音频驱动数字人人脸模型

1.LatentSync: Taming Audio-Conditioned Latent Diffusion Models for Lip Sync with SyncNet Supervision 字节 2024 文章地址&#xff1a;https://arxiv.org/pdf/2412.09262 代码地址&#xff1a;https://github.com/bytedance/LatentSync 训练推理都有 2.wan2.2-s2v …

CentOS部署ELK Stack完整指南

文章目录&#x1f680; ELK Stack 部署详解&#xff08;CentOS 7/8&#xff09;&#x1f4e6; 一、环境准备1. 关闭防火墙&#xff08;或开放端口&#xff09;2. 关闭 SELinux3. 安装基础依赖4. 验证 Java&#x1f53d; 二、下载并安装 ELK 组件1. 导入 Elastic GPG 密钥2. 创建…