必须确认系统使用cgroups v2,执行mount | grep cgroup查看是否为cgroup2类型,或检查/sys/fs/cgroup/cgroup.controllers是否存在且非空;若为v1则需升级内核或添加cgroup_no_v1=all参数重启。

确认系统用的是 cgroups v2 而不是 v1
别跳过这步——90% 的配置失败都卡在这儿。执行 mount | grep cgroup,看到 cgroup2 on /sys/fs/cgroup type cgroup2 才是 v2;如果只看到分散的 /sys/fs/cgroup/cpu、/sys/fs/cgroup/memory,说明你正在 v1 上硬套 v2 教程,所有 cpu.max、memory.max 都会报 No such file or directory。
更直接的验证方式:ls /sys/fs/cgroup/cgroup.controllers。v2 下该文件存在且内容非空(比如含 cpu 和 memory);v1 下这个路径根本不存在。
如果你确认是 v1,别改参数去“凑合”——要么升级内核,要么在 GRUB 里加 cgroup_no_v1=all 并重启。否则后续所有操作都是徒劳。
临时调试:用 sysfs 直接写入限制
适合快速验证或单次实验,但不持久。所有操作都在 /sys/fs/cgroup/ 下进行,无需手动挂载子系统。
- 创建控制组:
sudo mkdir /sys/fs/cgroup/myjob - 启用控制器(关键!否则限制不生效):
echo "+cpu +memory" | sudo tee /sys/fs/cgroup/myjob/cgroup.subtree_control - 设内存上限 512MB:
echo 512M > /sys/fs/cgroup/myjob/memory.max(设为0会立刻 kill 进程,设为max表示不限) - 设 CPU 使用率上限 1.5 核:
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(注意是cgroup.procs,不是tasks;后者只迁线程,前者迁整个线程组)
常见错误:bash: echo: write error: Invalid argument,多半是路径错、权限不足(必须 root)、控制器没启用,或写错格式(比如漏空格、单位写成 512MB 而非 512M)。
生产环境必须用 systemd 持久化
手写 sysfs 重启就丢,不能用于服务管理。systemd 是现代 Linux 的事实标准,原生支持 v2 语义,且自动处理层级、控制器启用、生命周期。
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
以 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/ 下创建子组并写入限制。注意:CPUQuota=150% 对应 v2 的 cpu.max 值,MemoryMax=512M 对应 memory.max,单位和行为完全一致。
容易被忽略的细节
memory.oom 默认不启用——即使写了 memory.max,超出也不会触发 OOM killer,只会阻塞分配。要真正启用,得确保 memory.oom 文件存在且值为 1(某些发行版需手动 echo)。
cpu.weight 是相对权重,只在资源争抢时起作用;cpu.max 才是硬限制。两者混用时,weight 不影响 quota 的绝对上限。
所有写入操作必须由 root 执行,且目标目录需提前创建。cgroup.procs 写入后,进程及其所有子进程自动归组,但已 fork 出的孤儿子进程不会自动迁移。

















