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

Linux cgroup 使用指南:从原理到实践

1 Linux cgroup 完全指南:从原理到实践

在 Linux 系统中,我们经常会遇到这样的问题:

  • 我有一个编译任务,不想让它占满整个 CPU,导致其他服务卡了

  • 我要跑一个测试程序,怕它内存用太多,把系统搞 OOM 了

  • 我有一堆进程,想限制它们总的磁盘 IO 速度,防止把硬盘打满

  • 我想防止有人搞 fork 炸弹,把系统的进程数耗尽

这些问题,都可以用cgroup来解决。

cgroup 是 Linux 内核提供的一个强大的资源管理机制,它可以把进程分组,然后对整个组做资源的限制、统计、隔离。它是容器技术(Docker、Kubernetes)的底层核心,也是系统管理员管理资源的利器。

这篇文章,我会带你从基础到实践,彻底搞懂 cgroup,让你能熟练用它来管理系统资源。


1.1 一、基础认知:什么是 cgroup?

cgroup 的全称是 Control Group(控制组),它是 Linux 内核的一个功能,用来将进程组织成一个层级的分组,然后对这个分组进行资源的管理:

  • 限制资源:限制整个组能使用的 CPU、内存、IO 等资源的上限

  • 统计监控:统计整个组的资源使用情况

  • 优先级控制:给不同的组分配不同的资源优先级

  • 隔离:将不同组的进程隔离开,互不影响

1.1.1 1.1 核心概念

  • 层级结构:cgroup 是树形的,父组的限制会作用于所有子组,子组的资源总和不能超过父组的限制

  • 子系统(Controller):也叫控制器,每个控制器负责管理一种资源,比如 CPU、内存、IO 等

  • 进程管理:你可以把任意进程加入到 cgroup 中,整个组的所有进程都会被统一管理

1.1.2 1.2 版本:v1 vs v2

cgroup 有两个大版本,v1 是旧版本,v2 是新版本,解决了 v1 的很多问题,现在新的系统(Ubuntu 22.04+、CentOS 9+、Debian 11+)默认都是 v2 了。

它们的区别:

特性cgroup v1cgroup v2
层次结构每个控制器独立的层级,你可以把进程放到不同控制器的不同组里统一的层级,所有控制器共享同一个分组结构
控制器分散的,每个控制器自己的规则统一的,所有控制器协同工作
进程管理可以把线程单独放到不同的组进程是原子的,整个进程的所有线程都在同一个组
功能基础的资源管理更强大的功能,比如 PSI 压力信息、统一的限制逻辑

💡 v1 已经被 deprecated 了,新的系统都推荐用 v2,这篇文章我们主要讲 v2,也会兼容 v1 的用法。

1.1.3 1.3 怎么查看你的系统用的是哪个版本?

执行这个命令,就能知道:

# 查看是否支持 cgroup v2test-f/sys/fs/cgroup/cgroup.controllers&&echo"✅ 你的系统支持 cgroup v2"||echo"❌ 你的系统只支持 cgroup v1"# 查看当前挂载的 cgroupmount|grepcgroup

如果输出了cgroup2 on /sys/fs/cgroup type cgroup2,说明你用的是 v2,完美。


1.2 二、核心子系统:cgroup 能管理哪些资源?

cgroup 通过不同的子系统(控制器)来管理不同的资源,常见的有这些:

子系统作用
cpu限制 CPU 的带宽,设置 CPU 优先级
cpuset绑定 CPU 核心和内存节点,适合 NUMA 架构的大服务器
memory限制内存使用,统计内存使用情况,支持 OOM 控制
io限制磁盘 IO 的速度、权重,控制磁盘的读写
pids限制组内的最大进程数,防止 fork 炸弹
hugetlb限制大页内存的使用
perf\_event性能事件的统计,用来做性能分析
rdma限制 RDMA 资源的使用

1.3 三、cgroup 能做什么?核心用途

cgroup 的用途非常广泛,最常见的有:

1.3.1 1. 资源限制

这是最常用的功能,你可以限制一个进程组最多用多少 CPU、多少内存、多少 IO,防止某个任务把整个系统搞挂了。

比如:

  • 跑编译任务的时候,限制它最多用 50% 的 CPU,不影响其他服务

  • 跑测试程序的时候,限制它最多用 1G 内存,防止 OOM

  • 备份的时候,限制磁盘 IO 速度,不影响线上业务

1.3.2 2. 资源优先级

你可以给不同的任务分配不同的资源权重,比如:

  • 线上的服务,给它高优先级,保证它能拿到足够的资源

  • 后台的批处理任务,给它低优先级,只有空闲的时候才让它跑

1.3.3 3. 资源统计

cgroup 会帮你统计整个组的资源使用情况,你可以很方便地知道一组进程用了多少 CPU、多少内存、多少 IO,用来做监控。

1.3.4 4. 进程隔离

cgroup 可以把进程隔离开,不同的组之间互不影响,这就是容器技术的核心:Docker、Kubernetes 就是用 cgroup 来隔离容器的资源的。

你平时用 Docker 的时候,docker run \-\-cpus=0\.5 \-\-memory=1g,其实就是底层创建了一个 cgroup,设置了这些限制!


1.4 四、实践操作:手把手教你用 cgroup

接下来,我们来动手实践,一步步教你怎么用 cgroup 来管理资源。

我们先讲cgroup v2的用法,因为新系统都是这个,然后再讲 v1 的兼容用法。

1.4.1 4.1 手动操作 cgroup v2

手动操作 cgroup 其实很简单,就是操作/sys/fs/cgroup下面的文件,cgroup 把接口暴露成了文件系统,你读写这些文件就能配置了。

1.4.1.1 步骤 1:创建你的 cgroup 分组

首先,创建一个目录,就是你的分组:

sudomkdir/sys/fs/cgroup/my_task
1.4.1.2 步骤 2:启用你需要的控制器

然后,你要告诉系统,这个分组要启用哪些控制器,比如我们要控制 CPU、内存、IO:

# + 表示启用,- 表示禁用sudosh-c'echo "+cpu +memory +io" > /sys/fs/cgroup/my_task/cgroup.subtree_control'
1.4.1.3 步骤 3:配置资源限制

现在,我们来设置各种资源的限制:

1.4.1.3.1 限制 CPU 使用率

我们想让这个组的任务,最多用 50% 的 CPU 核心:

# cpu.max 的格式是 配额/周期,单位是微秒# 100000 微秒就是 100ms,是默认的周期# 所以 50000 就是,每 100ms 里,最多用 50ms 的 CPU,也就是 50% 的使用率sudosh-c'echo 50000 > /sys/fs/cgroup/my_task/cpu.max'

如果你有多个 CPU 核心,比如 4 核,你想让它最多用 2 个核心,那就是200000,因为 2 * 100000 = 200000。

1.4.1.3.2 限制内存使用

我们想让这个组的任务,最多用 1G 的内存,超过了就会被 OOM kill:

sudosh-c'echo 1G > /sys/fs/cgroup/my_task/memory.max'

除了硬限制,还有软限制:

# 软限制:内存紧张的时候,优先回收这个组的内存sudosh-c'echo 900M > /sys/fs/cgroup/my_task/memory.high'# 最小保证:系统最少给这个组留这么多内存,内存紧张的时候优先保障它sudosh-c'echo 500M > /sys/fs/cgroup/my_task/memory.low'
1.4.1.3.3 限制磁盘 IO 速度

我们想限制这个组的磁盘读写速度,最多 1M/s,防止备份的时候把硬盘打满:

首先,你要知道你的磁盘的 major:minor 号,用lsblk就能看到:

lsblk# 输出比如:# sda 8:0 0 238.5G 0 disk

这里的8:0就是 sda 的设备号。

然后设置 IO 限制:

# 限制 sda 的读写速度,最多 1M/ssudosh-c'echo "8:0 rbps=1048576 wbps=1048576" > /sys/fs/cgroup/my_task/io.max'

1048576 就是 1M 的字节数,你要限制到 10M 就改成 10485760。

1.4.1.3.4 限制进程数量

防止 fork 炸弹,限制这个组最多有 100 个进程:

sudosh-c'echo 100 > /sys/fs/cgroup/my_task/pids.max'
1.4.1.4 步骤 4:把进程加入到组里

现在,我们把当前的 shell 加入到这个组里,这样我们在这个 shell 里跑的所有进程,都会被这些限制管着:

# $$ 就是当前 shell 的 PIDsudosh-c"echo$$> /sys/fs/cgroup/my_task/cgroup.procs"

你也可以把其他进程的 PID 写进去,比如把 PID 1234 加进去:echo 1234 \> /sys/fs/cgroup/my\_task/cgroup\.procs

1.4.1.5 步骤 5:测试!

现在,你可以在这个 shell 里跑任务了,比如跑个 CPU 压力测试:

# 安装压力测试工具sudoaptinstallstress-ng# 跑 CPU 压力stress-ng-c1

然后你开另一个终端,看 top,你会发现,这个进程的 CPU 使用率最多就是 50%!不会超过我们设置的限制!

完美!这就是 cgroup 的效果。

1.4.1.6 步骤 6:清理

用完了之后,要删除这个 cgroup,首先要把里面的进程移出来,或者 kill 掉,然后删除目录:

# 把进程移到根组,这样就能删了sudosh-c"echo$$> /sys/fs/cgroup/cgroup.procs"# 删除 cgroup 目录sudormdir/sys/fs/cgroup/my_task

1.4.2 4.2 更简单的方法:用 systemd slice

手动操作 sysfs 有点麻烦,有没有更简单的方法?

当然有!现在的系统都用 systemd,它已经帮你封装好了 cgroup 的操作,你用一条命令就能搞定!

比如,我们想创建一个受限的 shell,限制 CPU 50%,内存 1G:

sudosystemd-run--slice=my_task.slice--property=CPUQuota=50%--property=MemoryMax=1Gbash

就这一条命令!systemd 会自动帮你创建 cgroup,设置好限制,然后给你开一个新的 bash,你在这个 bash 里跑的所有进程,都会被限制!

是不是超级简单?不用记那些 sysfs 的路径了!

你还可以设置 IO 限制、进程数限制:

sudosystemd-run--slice=my_task.slice\--property=CPUQuota=50%\--property=MemoryMax=1G\--property=IOReadBandwidthMax="/dev/sda 1M"\--property=IOWriteBandwidthMax="/dev/sda 1M"\--property=TasksMax=100\bash

太方便了!这才是平时我们用的方法,不用手动搞那些文件。


1.4.3 4.3 兼容旧系统:cgroup v1 的用法

如果你的系统比较旧,还是用的 cgroup v1,操作稍微有点不一样,我也给你列出来:

# 1. 创建各个控制器的分组sudomkdir/sys/fs/cgroup/cpu/my_tasksudomkdir/sys/fs/cgroup/memory/my_tasksudomkdir/sys/fs/cgroup/blkio/my_task# 2. 设置 CPU 限制(v1 用的是 cpu.cfs_quota_us)sudosh-c'echo 50000 > /sys/fs/cgroup/cpu/my_task/cpu.cfs_quota_us'sudosh-c'echo 100000 > /sys/fs/cgroup/cpu/my_task/cpu.cfs_period_us'# 3. 设置内存限制sudosh-c'echo 1073741824 > /sys/fs/cgroup/memory/my_task/memory.limit_in_bytes'# 4. 设置 IO 限制sudosh-c'echo "8:0 1048576" > /sys/fs/cgroup/blkio/my_task/blkio.read_bps_device'sudosh-c'echo "8:0 1048576" > /sys/fs/cgroup/blkio/my_task/blkio.write_bps_device'# 5. 把进程加进去sudosh-c"echo$$> /sys/fs/cgroup/cpu/my_task/tasks"sudosh-c"echo$$> /sys/fs/cgroup/memory/my_task/tasks"sudosh-c"echo$$> /sys/fs/cgroup/blkio/my_task/tasks"

v1 因为每个控制器是独立的,所以你要把进程加到每个控制器的组里,有点麻烦,这也是为什么 v2 更好的原因。


1.5 五、进阶用法:cgroup 的高级功能

1.5.1 5.1 冻结 / 解冻进程组

你可以把整个 cgroup 的所有进程都冻结,暂停它们,然后需要的时候再解冻,这个太有用了!

比如,你要备份数据,怕进程在备份的时候改数据,就可以先把它们冻结,备份完了再解冻:

# 冻结所有进程sudosh-c'echo frozen > /sys/fs/cgroup/my_task/cgroup.freeze'# 查看状态cat/sys/fs/cgroup/my_task/cgroup.freeze# 输出 frozen# 解冻sudosh-c'echo thaw > /sys/fs/cgroup/my_task/cgroup.freeze'

1.5.2 5.2 资源压力监控(PSI)

cgroup v2 带来了一个非常有用的功能:PSI(Pressure Stall Information),它能告诉你系统的资源压力,也就是有多少时间,任务在等待资源。

比如,你可以看:

# 查看 CPU 压力cat/sys/fs/cgroup/my_task/cpu.pressure# 输出:some avg10=0.00 avg60=0.00 avg300=0.00 total=0# full avg10=0.00 avg60=0.00 avg300=0.00 total=0# 查看内存压力cat/sys/fs/cgroup/my_task/memory.pressure# 查看 IO 压力cat/sys/fs/cgroup/my_task/io.pressure

这个可以帮你判断,你的任务是不是在等资源,系统是不是过载了。

1.5.3 5.3 资源统计

cgroup 会帮你统计所有的资源使用情况,你可以很方便地监控:

# CPU 统计cat/sys/fs/cgroup/my_task/cpu.stat# 内存统计cat/sys/fs/cgroup/my_task/memory.stat# IO 统计cat/sys/fs/cgroup/my_task/io.stat# 进程数统计cat/sys/fs/cgroup/my_task/pids.stat

1.6 六、实际场景:怎么用 cgroup 解决你的问题?

1.6.1 场景 1:限制编译任务的资源

你要编译一个大项目,但是不想让它占满 CPU,影响线上的服务:

# 用 systemd 开一个受限的 shell,CPU 限制到 2 核,内存 4Gsudosystemd-run--slice=build.slice--property=CPUQuota=200%--property=MemoryMax=4Gbash# 然后在这个 shell 里跑编译make-j8

这样,编译最多用 2 个 CPU,不会影响其他服务。

1.6.2 场景 2:限制备份任务的 IO

你要跑备份,但是不想让备份的 IO 把硬盘打满,影响线上的数据库:

sudosystemd-run--slice=backup.slice--property=IOWriteBandwidthMax="/dev/sda 50M"bash# 然后在这个 shell 里跑备份tarzcf backup.tar.gz /data

这样,备份的写速度最多 50M/s,不会影响数据库。

1.6.3 场景 3:防止 fork 炸弹

你要跑一个不可信的脚本,怕它搞 fork 炸弹:

sudosystemd-run--slice=untrusted.slice--property=TasksMax=100bash# 然后在这个 shell 里跑脚本./untrusted_script.sh

就算它想 fork 炸弹,最多 fork 100 个进程,不会搞挂系统。

1.6.4 场景 4:Docker 容器的资源限制

你平时用 Docker 的时候,其实就是用的 cgroup:

dockerrun--cpus=0.5--memory=1g nginx

这行命令,就是 Docker 底层创建了一个 cgroup,限制了 CPU 50%,内存 1G,和我们刚才手动做的是一样的!


1.7 七、常见问题

1.7.1 1. 为什么我删除 cgroup 的时候提示 Device or resource busy?

因为你的 cgroup 里还有进程!你要先把里面的进程都移出来,或者 kill 掉,才能删除:

# 把进程移到根组sudosh-c"echo 你的PID > /sys/fs/cgroup/cgroup.procs"# 然后再删sudormdir/sys/fs/cgroup/my_task

1.7.2 2. 我把进程加到 cgroup 里,它的子进程会自动加进去吗?

会的!只要你在 cgroup 里 fork 子进程,子进程会自动继承父进程的 cgroup,不用你手动加。

1.7.3 3. cgroup 的限制是针对单个进程还是整个组?

整个组!所有在这个组里的进程,加起来的资源总和,不能超过你的限制,这就是 cgroup 最核心的价值,它是组级别的限制,而不是单个进程的。


1.8 总结

cgroup 是 Linux 系统管理资源的神器,它是容器技术的核心,也是系统管理员的利器。

通过这篇文章,你已经学会了:

  • cgroup 的基础概念和版本区别

  • 怎么用 cgroup 限制 CPU、内存、IO、进程数

  • 手动操作的方法,还有更简单的 systemd 方法

  • 进阶的冻结、监控功能

  • 实际场景的用法

现在,你已经可以熟练用 cgroup 来管理你的系统资源了,再也不用担心某个任务把系统搞挂了!

(注:文档部分内容可能由 AI 生成)

http://www.jsqmd.com/news/721766/

相关文章:

  • M4Markets vs FP Markets vs XM:平台稳定性与高波动时的表现
  • 孩子不爱背单词?试试让手指先「记住」——打字侠英语可以这样用
  • 【GPR回归预测】双向长短期记忆神经网络结合高斯过程回归(BiLSTM-GPR)的多变量回归预测 (多输入单输出)【含Matlab源码 15399期】
  • 从安防到短视频:聊聊视频分割技术在我们身边的5个真实应用
  • Cursor Free VIP终极指南:三步解锁Cursor Pro永久免费使用
  • 在 Windows 上使用 Hyper-V 虚拟机准备安装OpenClaw
  • 1993-2023年各国各行业IFR工业机器人数据
  • 你的棋盘格摆对了吗?Ubuntu 20.04 + ROS相机标定实战避坑指南(附常见错误排查)
  • 爆款引擎:2026流量内卷下的SEO破局密码
  • 如何开展高质量用户访谈?掌握 UX 研究的 4 个核心要素与提问艺术
  • 实战案例——AI智能客服机器人(全渠道发布)
  • HoRain云--SciPy科学计算库:Python数据分析的强大工具
  • 别再傻等IDEA的Maven骨架了!手把手教你用阿里云镜像5分钟搞定Web项目
  • 算法训练营第 17天 151.翻转字符串里的单词
  • 35块钱的国产开发板,用Docker搞定PyTorch模型TPU推理(MilkV Duo保姆级教程)
  • 用ESP32C3+Arduino IDE,5分钟搞定MiniMax大模型对话(附完整代码与避坑指南)
  • 虚拟主播必备!IndexTTS 2.0打造专属声音IP,情感可控超实用
  • 3步实现Windows系统性能翻倍:Winhance中文版终极优化指南
  • 文档分片上传、大文件处理方案(完整可直接集成)
  • UE5 Lumen性能调优实战:从30帧到60帧,我的项目优化踩坑记录
  • 006 刚体运动学与动力学基础
  • Flowchart-Vue:Vue.js流程图组件的完整指南与实战应用
  • 手把手教你用Kintex7 FPGA实现4路摄像头同屏显示(附Verilog源码)
  • # 发散创新:基于事件驱动的实时响应系统在运维自动化中的深度实践在现代云原生架构中,**事件响应机制*
  • LaTeX表格从入门到放弃?Overleaf里用booktabs和tabularx搞定复杂三线表和跨页长表
  • 树莓派Zero 2W无屏幕无网线开箱指南:从烧录到VNC远程桌面的保姆级避坑教程
  • HoRain云--超全SciPy安装指南,3种方法一键搞定
  • 人人选商城便捷的哪个好
  • 使用CodeBuddy为UE4项目合入HTML5能力
  • 捡漏价90块的乐视Astra Pro深度摄像头,我用Python+OpenCV让它动起来了(附完整代码)