cgroup v2 统一层级:限制与统计 CPU、内存、I/O 和进程数
cgroup v2 用单一层级树替代 v1 的多控制器挂载。每个 cgroup 是一个目录,控制器通过父目录的 cgroup.subtree_control 逐级下放;资源限制写在 memory.max、cpu.max、io.max、pids.max 等文件里。
/sys/fs/cgroup 可能是只读。--memory/--cpus/--pids-limit、Kubernetes 的 requests/limits 最终都落到 cgroup 文件;根因排查要看宿主机上的 cgroup 路径。# 判断当前是 v2、v1 还是 hybrid:cgroup2fs 表示 v2
stat -fc %T /sys/fs/cgroup
# 查看根 cgroup 可用的控制器
cat /sys/fs/cgroup/cgroup.controllers
# 创建一个 cgroup,并在根目录下放行 memory/cpu 控制器
sudo mkdir /sys/fs/cgroup/lab
echo "+memory +cpu" | sudo tee /sys/fs/cgroup/cgroup.subtree_control
# 把当前 shell 放进新 cgroup,限制为 0.5 个 CPU、512MiB 内存
echo $$ | sudo tee /sys/fs/cgroup/lab/cgroup.procs
echo "50000 100000" | sudo tee /sys/fs/cgroup/lab/cpu.max
echo 536870912 | sudo tee /sys/fs/cgroup/lab/memory.max
# 查看实际用量、限流与 OOM 事件
cat /sys/fs/cgroup/lab/memory.current
cat /sys/fs/cgroup/lab/cpu.stat
cat /sys/fs/cgroup/lab/memory.events
# 用 systemd 管理限额,避免与 systemd 自己写文件冲突
sudo systemd-run --scope -p MemoryMax=512M -p CPUQuota=50% bash
在已有 systemd unit 上改限制用 sudo systemctl set-property <unit> MemoryMax=1G CPUQuota=50%,不要直接 echo 到 unit 的 cgroup 文件,systemd 可能覆盖。
/sys/fs/cgroup/unified,看错目录会得出“控制器不存在”的结论;先用 stat -fc %T /sys/fs/cgroup 确认。EBUSY;要把进程移到叶子 cgroup。memory.max 触发的是 cgroup OOM kill,进程常见退出码 137;memory.high 只是节流,不会直接杀进程,两者不要混用。cpu.max 的格式是 quota period(微秒),50000 100000 才是 0.5 CPU;只写一个数字会被拒绝。cpu.stat 的 nr_throttled/throttled_usec 会增长,但整体 CPU 使用率可能不高,容易误判为“没有压力”。io.max 需要整块设备的 major:minor,不能写分区;先用 lsblk -o NAME,MAJ:MIN 确认,且部分虚拟盘不支持。systemd-cgls 或 /proc/<pid>/cgroup 查。memory.current,容器“没跑多少进程却 OOM”时先看 memory.stat 的 file 与 shmem。memory.high 和 memory.max 的行为差异是什么?cpu.max 会报错或文件不存在?stat -fc %T /sys/fs/cgroup 返回 cgroup2fs 是 v2,返回 tmpfs 通常是 v1 或 hybrid;hybrid 下 v2 挂载点一般在 /sys/fs/cgroup/unified。memory.high 触发节流式回收,可能造成延迟但不直接杀进程;memory.max 是硬上限,回收失败后触发 cgroup OOM。cgroup.subtree_control 中启用后才会出现在子目录;若父 cgroup 同时有进程,还可能因 no-internal-processes 约束失败。