cgroups v2是当前唯一应配置的版本,v1已被弃用;验证方法为检查mount输出含cgroup2或存在/sys/fs/cgroup/cgroup.controllers;配置需通过/sys/fs/cgroup树或systemd持久化,注意memory.oom需手动启用。

Cgroups v2 是当前唯一值得投入时间配置的版本,v1 已被主流发行版弃用,手动挂载多子系统、混用控制器极易出错。
确认系统运行的是 cgroups v2
别跳过这步——很多“教程失效”问题根源在此。执行 mount | grep cgroup,看到类似 cgroup2 on /sys/fs/cgroup type cgroup2 (rw,relatime,seclabel) 才是 v2;若只看到 cgroup(无 2)且路径分散在 /sys/fs/cgroup/cpu、/sys/fs/cgroup/memory 等,说明你正踩在 v1 的坑里。
更直接的验证方式:ls /sys/fs/cgroup/cgroup.controllers。v2 下该文件存在且非空;v1 下该路径根本不存在。
如果确认是 v1,别挣扎着学旧参数——升级内核或改用 systemd 启动时加 cgroup_no_v1=all,否则后续所有 cpu.max、memory.max 都会报 No such file or directory。
用 sysfs 直接写入限制(临时调试用)
v2 下所有操作都归一到 /sys/fs/cgroup 树下,无需 mount -t cgroup 或 cgcreate。但注意权限:必须 root,且目录需手动创建。
- 创建控制组:
mkdir /sys/fs/cgroup/myjob - 设内存上限 512MB(触发 OOM killer):
echo 512M > /sys/fs/cgroup/myjob/memory.max;设为0会立刻 kill 进程,设为max表示不限制 - 限 CPU 使用率 1.5 核(即 150%):
echo 150000 100000 > /sys/fs/cgroup/myjob/cpu.max(格式是quota period,默认 period=100000μs,所以 150000/100000 = 1.5) - 把进程加入:
echo $PID > /sys/fs/cgroup/myjob/cgroup.procs(不是tasks,后者只迁线程,cgroup.procs迁整个线程组)
常见错误:bash: echo: write error: Invalid argument —— 多半是写错了格式(比如漏了空格)、路径不存在,或该子系统未启用(检查 /sys/fs/cgroup/cgroup.controllers 是否含 cpu 和 memory)。
用 systemd 持久化资源限制(生产环境唯一推荐方式)
手写 sysfs 只适合调试。服务一旦重启、机器重装,限制全丢。systemd 是现代 Linux 的事实标准管理器,它原生支持 cgroups v2 语义。
以 myapp.service 为例,在 /etc/systemd/system/myapp.service 中添加:
[Service] MemoryMax=512M CPUQuota=150% IOWeight=50
然后执行:
systemctl daemon-reloadsystemctl start myapp.service
systemd 会自动在 /sys/fs/cgroup/system.slice/myapp.service/ 下创建对应子组并写入限制。不用管 cpu.max 还是 cpu.weight——CPUQuota 自动映射为 v2 的 cpu.max,IOWeight 映射为 io.weight。
⚠️ 注意:CPUQuota=150% 不等于 “最多用 1.5 核”,而是“每 100ms 周期内最多用 150ms CPU 时间”,实际并发能力仍取决于系统空闲核数。真要绑核,请用 CPUAffinity=0-1(仅限 v2 的 cpuset 控制器)。
为什么 memory.max 设了却没触发 OOM?
这是最常被忽略的细节:cgroups v2 的 memory controller 默认不启用 OOM killer,除非你显式设置了 memory.oom.group 或依赖内核默认行为(多数发行版已默认开启)。但更稳妥的做法是确认 memory.oom 文件值:
cat /sys/fs/cgroup/myjob/memory.oom 应返回 1;若为 0,执行 echo 1 > /sys/fs/cgroup/myjob/memory.oom。
另一个干扰项:进程使用的 page cache(如读文件缓存)也计入 memory.max,但 kernel 会优先回收这部分内存,而非直接 OOM。想精准压测内存分配行为,得用 mmap(MAP_ANONYMOUS) 类型的程序(如 Python 的 ' ' * N),避开缓存干扰。











