Linux cgroup v2 资源控制实战:限制进程 CPU/内存/IO,systemd slice 管理

Linux cgroup v2 资源控制实战:限制进程 CPU/内存/IO,systemd slice 管理

Linux cgroup(Control Groups)是内核提供的一种机制,用于限制、记录和隔离进程组的资源使用。cgroup v2 是其第二代实现,统一了层级结构,简化了接口设计,并与 systemd 深度集成。本文将带你从零开始掌握 cgroup v2 的核心用法,包括 CPU、内存、IO 限制,以及通过 systemd slice 进行服务资源管理。


环境要求

本教程在以下环境中测试通过:

  • 操作系统:Ubuntu 22.04 / Debian 12 / CentOS Stream 9
  • 内核版本:5.10+(建议 6.x)
  • systemd 版本:245+

推荐使用 雨云服务器 rainyun-com 进行实验,注册填优惠码 2026off 领 5 折优惠券。推荐机型:2 核 4GB Linux 云服务器,足以运行本文所有实验场景,价格实惠,按量计费,适合学习测试。


核心概念

cgroup v1 vs cgroup v2

cgroup v1 采用多层级结构,每种资源(cpu、memory、blkio 等)有独立的层级树,管理复杂,容易出现资源竞争问题。

cgroup v2 采用统一层级,所有控制器挂载在同一棵树下,接口更简洁,解决了 v1 中的多个设计缺陷:

特性 cgroup v1 cgroup v2
层级结构 多层级 统一层级
接口路径 /sys/fs/cgroup/<controller>/ /sys/fs/cgroup/
资源控制粒度 各控制器独立 统一协调
systemd 集成 部分支持 原生支持
PSI 支持 不支持 支持

主要控制器

  • cpu:限制 CPU 使用时间(配额/周期)
  • memory:限制内存和 swap 使用
  • io:限制块设备读写速率/IOPS
  • pids:限制进程数量
  • cpuset:绑定 CPU 核心和 NUMA 节点

systemd slice 概念

systemd 使用 slice、scope、service 三种单元类型管理 cgroup:

  • slice :资源控制层级的容器单元(如 system.slice、user.slice)
  • scope:由外部程序创建的进程组
  • service:由 systemd 管理的服务

配置步骤

第一步:确认 cgroup v2 已启用

bash 复制代码
# 检查挂载类型
mount | grep cgroup
# 应显示 cgroup2 类型

# 或检查文件
stat -fc %T /sys/fs/cgroup/
# 输出 cgroup2fs 说明已启用 v2

若系统使用混合模式,可通过内核参数强制启用纯 v2:

bash 复制代码
# 编辑 GRUB 配置
sudo vim /etc/default/grub

# 在 GRUB_CMDLINE_LINUX 中添加
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"

sudo update-grub
sudo reboot

第二步:手动创建 cgroup 并限制 CPU

bash 复制代码
# 创建自定义 cgroup
sudo mkdir /sys/fs/cgroup/myapp

# 启用 cpu 和 memory 控制器(需在父级启用)
echo "+cpu +memory +io" | sudo tee /sys/fs/cgroup/cgroup.subtree_control

# 设置 CPU 限制:每 100ms 周期内最多使用 50ms(即 50% 单核)
echo "50000 100000" | sudo tee /sys/fs/cgroup/myapp/cpu.max

# 将进程加入 cgroup(替换 PID 为实际进程号)
echo <PID> | sudo tee /sys/fs/cgroup/myapp/cgroup.procs

第三步:限制内存使用

bash 复制代码
# 设置内存上限为 512MB
echo $((512 * 1024 * 1024)) | sudo tee /sys/fs/cgroup/myapp/memory.max

# 设置内存软限制(建议值)
echo $((400 * 1024 * 1024)) | sudo tee /sys/fs/cgroup/myapp/memory.high

# 禁用 swap(可选)
echo 0 | sudo tee /sys/fs/cgroup/myapp/memory.swap.max

# 查看当前内存使用
cat /sys/fs/cgroup/myapp/memory.current

第四步:限制磁盘 IO

bash 复制代码
# 查看块设备 major:minor 号
ls -l /dev/sda
# 例如 8:0

# 限制读写速率:最大读 50MB/s,写 20MB/s
echo "8:0 rbps=52428800 wbps=20971520" | sudo tee /sys/fs/cgroup/myapp/io.max

# 限制 IOPS:最大读 1000 IOPS,写 500 IOPS
echo "8:0 riops=1000 wiops=500" | sudo tee /sys/fs/cgroup/myapp/io.max

# 查看 IO 统计
cat /sys/fs/cgroup/myapp/io.stat

第五步:使用 systemd slice 管理服务资源

创建自定义 slice 单元文件:

bash 复制代码
sudo vim /etc/systemd/system/myapp.slice
ini 复制代码
[Unit]
Description=MyApp Resource Slice
Before=slices.target

[Slice]
# CPU 限制:总 CPU 的 30%(相对权重)
CPUQuota=30%

# 内存限制
MemoryMax=1G
MemoryHigh=800M

# IO 权重(100 为默认值,越小优先级越低)
IOWeight=50

将服务绑定到该 slice:

bash 复制代码
sudo vim /etc/systemd/system/myapp.service
ini 复制代码
[Unit]
Description=MyApp Service
After=network.target

[Service]
Slice=myapp.slice
ExecStart=/usr/bin/myapp
Restart=always

[Install]
WantedBy=multi-user.target
bash 复制代码
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

# 查看资源使用情况
systemctl status myapp.service
systemd-cgtop

实战示例

场景一:限制 Python 爬虫的 CPU 占用

bash 复制代码
# 启动爬虫后获取 PID
python3 spider.py &
SPIDER_PID=$!

# 创建限制组,CPU 不超过 25%
sudo mkdir /sys/fs/cgroup/spider
echo "25000 100000" | sudo tee /sys/fs/cgroup/spider/cpu.max
echo $((256 * 1024 * 1024)) | sudo tee /sys/fs/cgroup/spider/memory.max
echo $SPIDER_PID | sudo tee /sys/fs/cgroup/spider/cgroup.procs

# 验证限制效果
top -p $SPIDER_PID

场景二:使用 systemd-run 临时限制命令

bash 复制代码
# 在限制资源的环境中运行命令(无需手动创建 cgroup)
sudo systemd-run \
  --scope \
  --slice=myapp.slice \
  -p CPUQuota=20% \
  -p MemoryMax=256M \
  -- python3 heavy_task.py

场景三:查看 PSI(压力指标)

cgroup v2 支持 PSI(Pressure Stall Information),可监控资源压力:

bash 复制代码
# 查看 CPU 压力
cat /sys/fs/cgroup/myapp/cpu.pressure

# 查看内存压力
cat /sys/fs/cgroup/myapp/memory.pressure

# 查看 IO 压力
cat /sys/fs/cgroup/myapp/io.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

常见问题

Q:设置 cpu.max 后为何没有限制效果?

A:检查父级 cgroup 是否已启用 cpu 控制器。执行 cat /sys/fs/cgroup/cgroup.subtree_control 确认包含 cpu,若没有则执行 echo "+cpu" | sudo tee /sys/fs/cgroup/cgroup.subtree_control。

Q:memory.max 设置后进程被 OOM Kill 怎么办?

A:可先设置较宽松的 memory.high(软限制),系统会在达到该值时主动回收内存并触发 throttle,而非直接 kill。只有超过 memory.max 时才会触发 OOM。

Q:如何让 cgroup 设置在重启后持久化?

A:直接操作 /sys/fs/cgroup/ 下的文件不会持久化。推荐通过 systemd slice/service 单元文件管理,或使用 cgconfig 工具(需安装 libcgroup-tools)配合 /etc/cgconfig.conf。

Q:systemd-cgtop 显示的资源与 top 有差异?

A:systemd-cgtop 显示的是 cgroup 维度的聚合数据,而 top 显示单进程数据。两者统计维度不同,属正常现象。

Q:如何删除自定义 cgroup?

A:先将所有进程移出(移到父级 cgroup),再使用 rmdir 删除目录:

bash 复制代码
# 将进程移到根 cgroup
echo <PID> | sudo tee /sys/fs/cgroup/cgroup.procs
# 删除空目录
sudo rmdir /sys/fs/cgroup/myapp

相关推荐
zxanz14 分钟前
证书运维自动化,守住业务 HTTPS 底线
运维·https·自动化
vipxieliang9 分钟前
Service Mesh 可观测性:分布式追踪、指标与日志的统一方案
运维
DYWorker00124 分钟前
第 1-10 课: 横切设施:锁、RCU、安全与观测怎么选?
linux
臻一26 分钟前
rk3568---ftp无法连接
linux·ftp·3568
云飞云共享云桌面1 小时前
智能装备工厂研发部门多设计师共享一台SolidWorks服务器做设备装配建模
运维·服务器·网络·人工智能·3d·自动化·制造
Elastic 中国社区官方博客1 小时前
Elastic 在《Forrester Wave™:2026 年第四季度智能运维平台》报告中被评为强劲表现者
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索
简简单单就是我_hehe1 小时前
一次 ClickHouse 服务器磁盘告警的排查与修复实录
java·服务器·前端
自由彩虹1 小时前
靶场通关16--victim1
linux·服务器·网络·安全·web安全·网络安全
叼烟扛炮1 小时前
Linux 学习笔记(三十九):网络基石——TCP/IP 模型与 UDP 实战
linux·运维·网络·笔记·学习·tcp/ip
闲云野鹤在人间1 小时前
头秃修炼手册:StorageClass+StatefulSet+ETCD 全套渡劫笔记
linux·数据库·笔记·云原生·kubernetes·etcd