Linux cgroup v2 unified hierarchy 的 memory + cpu + io 控制器统一管理

1次阅读

memory.high 不会触发 oom 杀进程,仅在内存压力下尽力回收页面;真正触发 oom killer 的是 memory.max 硬限制。

Linux cgroup v2 unified hierarchy 的 memory + cpu + io 控制器统一管理

memory.high 触发后进程真的会被 OOM 杀掉吗?

不会,memory.high 是软限制,内核只会在内存压力下尽力回收该 cgroup 的页面,不满足时会先踢出 page cache、swap out 匿名页,甚至延迟分配——但不会直接 kill 进程。真要杀,得靠 memory.max(硬上限)触发 OOM killer。

  • memory.max 设为 0 表示无限制;设为 1G 之类具体值后,一旦实际使用超限,内核立刻选一个进程干掉
  • memory.high 推荐设为略高于预期峰值(比如峰值 800M,设 900M),给回收留缓冲,避免抖动
  • 查看是否被压:读 /sys/fs/cgroup/mygroup/memory.events,关注 high 字段计数增长,不是 oom 才说明你在用对路子

cgroup v2 下 cpu.weight 和 cpu.max 怎么配才不冲突?

cpu.weight(默认 100)管的是「相对份额」,cpu.max(如 50000 100000)管的是「绝对带宽上限」,两者同时生效,但优先级不同:先按 cpu.max 切总带宽,再在剩余带宽里按 cpu.weight 分。

  • cpu.max 第一个值是微秒(us),第二个是周期(us),50000 100000 = 50% CPU;设成 max 表示不限制
  • 如果只设 cpu.weight 不设 cpu.max,cgroup 可能吃满所有空闲 CPU,其他组没机会抢到
  • 常见错误:把 cpu.max 设太小(比如 1000 100000 = 1%),又把 cpu.weight 调很高,结果既抢不到资源,又没弹性空间

io.weight 对不同 I/O 类型(sync/async, buffered/direct)有效吗?

只对基于 bfq 调度器的 同步 buffered I/O 有效;对 direct I/O、异步 I/O(libaio/io_uring)、以及 noop/deadline 调度器下的 I/O 基本无效。

  • 确认调度器:cat /sys/block/nvme0n1/queue/scheduler,输出含 [bfq] 才行
  • io.weight 范围是 1–1000,默认 100;设为 10 表示该组只拿约 1% 的 IO 带宽(相比 weight=1000 的组)
  • 容易踩坑:在容器里跑 postgresqlredis(常开 O_DIRECT),这时 io.weight 形同虚设,得靠 io.max(bps/iops 限速)来控

统一 hierarchy 下如何让 memory + cpu + io 控制器真正协同生效?

必须确保所有控制器都在同一 cgroup 路径下启用,且挂载时没漏掉 memorycpuio —— v2 要求「全有或全无」,哪怕只缺一个,整个路径都进不了 unified 模式。

  • 挂载命令必须带完整 controller list:mount -t cgroup2 none /sys/fs/cgroup -o clone_children(注意不是 cgroup v1)
  • 创建子 cgroup 后,往 cgroup.controllers 写入要启用的控制器:echo "+memory +cpu +io" > cgroup.controllers
  • 若写入失败(报 Device or Resource busy),说明有进程已在这个 cgroup 下运行,得先移出再操作
  • 最容易被忽略的一点:systemd 默认把服务塞进 /sys/fs/cgroup/system.slice/xxx.service,但那里默认只启了 cpumemoryio 得手动加进去,否则 IO 控制永远不生效
text=ZqhQzanResources