Linux cgroup 在资源控制中的作用

8次阅读

cgroup是内核级强制资源控制机制,能硬性限制CPU、内存、IO等资源;超限时进程被OOM killer杀掉或等待下个调度周期。

Linux cgroup 在资源控制中的作用

linux cgroup 是什么,它真能限制进程资源吗

能,而且是内核级强制控制。cgroup(control group)不是用户态工具或监控代理,而是 Linux 内核提供的资源隔离与分组管理机制。只要正确挂载、配置并把进程加入对应 cgroup,CPU、内存、IO 等资源上限就会被硬性执行——超限时,比如内存用超 memory.max,进程会直接被 OOM killer 杀掉;CPU 时间超配额,就只能等下个调度周期。

为什么 memory.max 设了却没生效

常见原因是没启用 memory controller,或者进程没真正进入目标 cgroup。从 kernel 5.8+ 开始,memory controller 默认不启用,需在启动参数中显式添加 cgroup_enable=memory 并配合 swapaccount=1(若需限制 swap)。另外,仅创建目录、写入 memory.max 不够,必须把进程 PID 写入该 cgroup 的 cgroup.procstasks 文件:

echo $PID > /sys/fs/cgroup/mygroup/cgroup.procs

注意:cgroup.procs 写入的是线程组 ID(即主线程 PID),tasks 才是单个线程 ID;混用会导致部分线程未受控。

  • systemd 启动的服务默认在自己的 scope 下,需用 SystemMaxMemoryMemoryMax= 在 unit 文件里配置,而非手动改 cgroup 文件
  • 容器运行时(如 runc)通常自动设置 cgroup,但 debug 时建议检查 /proc/$PID/cgroup 确认进程归属
  • memory.maxmax 表示不限制,不是“最大值”,别误设成字符串 “max”

cpu.maxcpu.weight 到底怎么选

两者定位完全不同:cpu.weight(cgroup v2)是相对权重,用于公平调度,不设硬上限;cpu.max 才是绝对配额,格式为 "max us/sec",例如 "50000 100000" 表示每 100ms 最多用 50ms CPU 时间。

实际场景中:

  • 做资源保障型服务(如数据库主实例),优先用 cpu.max 防止单一进程吃满 CPU
  • 做批处理任务混部(如日志压缩 + 实时 API),用 cpu.weight 更灵活,避免低权任务完全饿死
  • cpu.max 对短时突发无效——它只在周期性配额检查点(默认 100ms)生效,高频小任务可能连续抢到多个周期的额度

为什么 cgroup v1 和 v2 混用会出问题

根本原因是两者不兼容:v1 按子系统挂载(cpumemory 各自独立挂载),v2 是统一挂载单棵树,所有控制器必须同时启用或禁用。如果你看到 /sys/fs/cgroup/cpu/sys/fs/cgroup/unified 同时存在,说明系统处于混合模式,此时 systemd、docker 等组件行为不可预测。

确认方式:

mount | grep cgroup

理想输出应只含一行 cgroup2 on /sys/fs/cgroup type cgroup2。若要彻底切换到 v2:

  • 内核启动参数加 systemd.unified_cgroup_hierarchy=1
  • 禁用旧版控制器:确保 /proc/sys/kernel/cgroup_disable 为空或不含 cpumemory
  • Docker 20.10+ 默认支持 v2,但需在 /etc/docker/daemon.json 中显式设 "cgroup-parent": "/docker" 类路径,否则可能 fallback 到 v1

cgroup 的复杂性不在语法,而在它和调度器、OOM killer、page cache 回收等内核子系统的耦合深度——一个配置项改错,可能让延迟毛刺变高,或让内存回收卡住整个节点。动手前,先看 /sys/fs/cgroup/xxx/cgroup.events 里的 populatedlow 事件,比盲目调参更可靠。

text=ZqhQzanResources