Cgroup v2和v1的区别

本文主要介绍cgroup v2和v1的区别。

Cgroups(Control Groups)是 Linux 内核提供的一种资源限制、审计与隔离机制。它允许

将进程分组,并对这些组应用资源限制(如 CPU、内存、IO 等)。目前存在两个主要版本:cgroup v1cgroup v2

1. cgroup v1 和 v2 的主要区别

1.1. 层级结构设计

cgroup v1:

  • 每个子系统(controller,如 cpumemory)可以挂载在不同的层级上

  • 不同资源控制器可以拥有不同的层级结构

  • 同一个进程可以出现在多个层级中(因为各 controller 独立)。

缺点

  • 管理复杂:不同 controller 的层级可能冲突。

  • 用户空间程序难以协调多个资源的管理。

cgroup v2:

  • 所有 controller 使用统一的单层次树形结构(single unified hierarchy)。

  • 每个进程只能属于一个 cgroup。

  • 更简洁、更一致、更容易管理。


1.2. 资源控制行为改进

cgroup v1:

  • 控制器之间独立实现,行为不一致。

  • 有些 controller 行为奇怪或不完整(如 memory 的 oom 行为、cpu shares)。

cgroup v2:

  • 控制器重写或增强,行为更加一致和合理。

  • 更加严格的限制与传播模型,例如:

    • 子 cgroup 的资源使用总量不能超过父级分配。

    • 支持精细的 IO 带宽控制(通过 io.max 取代 v1 的 blkio 控制器)。

    • 内存高水位线通知 (memory.high),支持 memory pressure 的渐进控制。


1.3. 配置接口(文件系统)

cgroup v1:

  • 每个 controller 会暴露多个文件,如 memory.limit_in_bytescpu.shares

  • 文件名不一致、语义也不统一。

cgroup v2:

  • 使用统一的接口命名,如:

    • memory.max 替代 memory.limit_in_bytes

    • cpu.max 替代 cpu.cfs_quota_us

  • 配置方式更简洁、更一致。


1.4.进程行为控制

cgroup v1:

  • 没有明显的限制,父级 cgroup 中的进程可以和子 cgroup 并存。

  • 容易产生“叶子节点”和“中间节点”混用的问题。

cgroup v2:

  • 中间节点不能包含进程,只有叶子节点可以运行进程。

  • 强制遵循“控制权不可传递”,资源必须分配到底层。


1.5. 内核支持和兼容性

  • cgroup v1:默认启用在旧版本 Linux(如 CentOS 7)。

  • cgroup v2:Linux kernel 4.5 引入,5.x 逐渐成熟,现在主流发行版(如 Fedora、Ubuntu 22.04+)已默认使用 cgroup v2。


1.6. 总结对比表

特性 cgroup v1 cgroup v2
控制器挂载 多层级结构 单一统一层级
文件接口 各控制器自定义 统一命名和行为
进程限制 可混用中间/叶子节点 只能在叶子节点运行
控制器一致性 不一致,独立实现 统一,行为一致
内核支持 老系统默认使用 新内核推荐使用

2. Cgroup v2的资源隔离性优化

2.1. 统一的层级结构,消除隔离漏洞

📌 v1 问题:

  • 每个 controller(如 cpu、memory、blkio)可以挂载在不同的层级

  • 一个进程可能出现在多个 cgroup(分别控制不同资源),导致资源隔离不一致或冲突

    • 例如:cpu 限制在 /cg1memory 限制在 /cg2,无法准确控制组合资源使用。

✅ v2 优化:

  • 所有 controller 使用统一的单层级树(unified hierarchy)。

  • 每个进程只能存在于一个 cgroup 中,所有资源限制统一生效。

  • 隔离策略具有一致性和传递性,防止“某些资源没隔离”的情况。

🔍 好处: 避免多 controller 层级不一致造成的隔离漏洞,资源限制行为更可预期。


2.2. 增强的内存隔离机制

v2 新特性:

  • 引入 memory.high(软限制):超过后触发页回收(但不立即 OOM)。

  • 强化 memory.max(硬限制):超过直接触发 OOM。

  • 支持 OOM group kill:可将整个 pod 内的多个进程作为一组统一 kill。

v1 缺陷:

  • 只有 memory.limit_in_bytes,OOM 后果不可控,不能渐进响应内存压力。

🔍 好处:

  • 实现更平滑的资源压力反馈,容器在压力下可“自救”。

  • 防止 noisy neighbor(内存噪声邻居)干扰其他 pod。


2.3. 更精准的 CPU 调度控制

v2 改进:

  • 使用 cpu.max 设置 CPU 带宽上限,精度提升。

  • 引入 cpu.weight(0~10000):代替 v1 的 cpu.shares,线性、可加性更强。

  • 支持 按比例调度,防止低优先 pod 抢占高优先资源。

v1 问题:

  • cpu.shares 非线性、不稳定。

  • cfs_quota 控制粒度粗,容易造成抖动。

🔍 好处: CPU 时间分配更加公平和稳定,防止容器之间 CPU 抢占影响彼此性能


2.4. IO 隔离更细粒度和可控

v2 提供:

  • io.max:按设备设置带宽/IOPS 上限。

  • io.weight:设置权重调度优先级。

例如:

echo "8:0 rbps=1048576 wbps=1048576" > io.max # 限制 /dev/sda 读写速率为 1MB/s

v1 问题:

  • 使用 blkio.*,行为依赖块设备,支持不一致,精度低。

  • IOPS 与带宽不能同时控制,难以部署混合 workload。

🔍 好处: 提供IO 抢占控制防止磁盘打满拖垮其他 pod,对数据库/日志类容器特别有利。


2.5. 压力感知能力(PSI)提升感知性隔离

v2 新特性:

  • 原生支持 Pressure Stall Information (PSI)

    • 提供 cpu.pressurememory.pressureio.pressure 等指标。

    • 显示资源的阻塞比例、等待时间(如 some / full stall)。

v1 不支持 PSI。

🔍 好处:

  • 可用于调度器做资源感知(例如 Koordinator、Kubelet QRM)。

  • 实现动态隔离/弹性扩缩容策略,提前感知资源瓶颈。


2.6. 进程放置约束提升层级隔离清晰度

v2 要求:

  • 只有叶子节点可以运行进程。

  • 中间节点用于组织和资源继承,避免"父子 cgroup 都有进程"的资源争用。

v1 无此限制,容易产生隔离混乱。

🔍 好处: 保证资源继承链明确,避免“父子抢资源”问题。


2.7. 更好的资源传播和继承规则

  • v2 明确规定:子 cgroup 的资源配额不可超过父级设置

  • v1 中 controller 行为不一致,有些 controller(如 cpu)资源限制不会级联。

🔍 好处: 资源隔离链路完整,防止容器层越权使用 pod 层的资源限制之外的资源

2.8. 资源隔离性提示对比

功能点 cgroup v1 cgroup v2 提升点
层级一致性 ❌ 多层级 ✅ 单层级 统一控制、隔离不混乱
内存隔离 一刀切、容易 OOM 支持 memory.high + OOM group kill 渐进隔离、防止雪崩
CPU 限制 粒度粗、抢占明显 带宽精细 + weight 线性 可控公平调度
IO 控制 粗糙、支持差 io.max, io.weight 精细控制 IO 不互相影响
PSI 支持 可用于资源压力调度
运行位置限制 无要求 只能在叶子节点 结构清晰,避免冲突
资源继承传播 弱、不一致 强、自动级联 隔离逻辑严密

3. cgroup v1 和 cgroup v2 的层级结构差异

场景:一个 Pod 内有两个容器 containerA 和 containerB

3.1. cgroup v1 的层级格式(多树结构)

在 cgroup v1 中,每个 controller(如 memory、cpu)是单独挂载的子系统,彼此独立,层级不一致:

# memory 子系统的 cgroup 层级:
/sys/fs/cgroup/memory/kubepods/pod123/containerA
/sys/fs/cgroup/memory/kubepods/pod123/containerB

# cpu 子系统的 cgroup 层级可能不同(可能是按 qos 再分层):
/sys/fs/cgroup/cpu/kubepods/burstable/pod123/containerA
/sys/fs/cgroup/cpu/kubepods/burstable/pod123/containerB

# blkio 也可能完全不同
/sys/fs/cgroup/blkio/k8s.io/pod123/containerA
/sys/fs/cgroup/blkio/k8s.io/pod123/containerB

问题

  • 资源限制配置分散,隔离策略难以统一。

  • kubelet 或 CRI 管理难度高,不易维护。

  • 某些 controller 中,父子 cgroup 会混放进程,造成资源混抢。

3.2. cgroup v2 的层级格式(统一树结构)

cgroup v2 所有控制器(memory、cpu、io)使用统一的挂载点,并严格限制结构层次:

# 所有 controller 都在统一挂载点 /sys/fs/cgroup
/sys/fs/cgroup/kubepods.slice/
└── kubepods-burstable.slice/
    └── kubepods-burstable-pod123.slice/
        ├── containerA.scope/
        └── containerB.scope/

说明:

  • 所有资源限制(CPU、memory、IO)都在 /sys/fs/cgroup/kubepods-burstable-pod123.slice/containerA.scope/ 这个目录中。

  • 每个 container 的资源控制逻辑清晰统一。

  • 不允许 container 和 pod 同时在一个目录中运行进程(叶子节点原则)。

3.3. 对比总结表

项目 cgroup v1 cgroup v2
控制器层级 每个控制器独立(多棵树) 所有控制器统一(单棵树)
示例目录结构 memory/..., cpu/..., blkio/... /sys/fs/cgroup/...(统一)
资源隔离配置 分散在不同路径 集中在统一路径
父子节点进程混放 可能混放 严格禁止,父不能运行进程
管理复杂度 高,需多层次同步 低,集中管理

4. cgroup v2 常用资源限制文件汇总

4.1. CPU 控制器文件(cpu.*

文件名 用途说明 示例值说明
cpu.max 限制 CPU 最大使用带宽,格式为 quota period 50000 100000:每 100ms 最多用 50ms,即 0.5 CPU
cpu.weight 设置 CPU 相对调度权重(1~10000) 100(默认)权重越高调度越积极
cpu.stat CPU 使用统计 包含 usage_usecthrottled_usec 等累计指标
cpu.pressure CPU 资源压力监控(PSI) some avg10=0.00 avg60=0.00 avg300=0.00 total=0

4.2. 内存控制器文件(memory.*

文件名 用途说明 示例值说明
memory.max 内存硬限制,超出则 OOM 536870912 表示 512MB
memory.high 内存软限制,超过则触发回收(不 OOM) 268435456 表示 256MB
memory.low 设置最低保证值,低于此值尽量不回收 134217728 表示 128MB
memory.current 当前使用内存 123456789 表示当前用约 117MB
memory.stat 内存使用细节统计 包括 anon、file、rss、slab、cache 等
memory.events 记录 OOM、high 命中等事件次数 high 1, oom 0
memory.pressure 内存 PSI 指标 some avg10=0.10 avg60=0.08 avg300=0.05 total=1234

4.3. IO 控制器文件(io.*

文件名 用途说明 示例值说明
io.max 限制块设备 IO 带宽/IOPS 8:0 rbps=1048576 wbps=1048576 表示限速 1MB/s
io.weight 设置相对 IO 权重(1~10000) 100(默认)
io.stat 实际 IO 统计(读写字节/次数) 8:0 rbytes=12345678 wbytes=87654321 rios=123 wios=321
io.pressure IO PSI 指标 some avg10=0.00 avg60=0.00 avg300=0.00 total=0

4.4. 进程数控制器文件(pids.*

文件名 用途说明 示例值说明
pids.max 限制最大进程/线程数 512:最多允许 512 个进程/线程
pids.current 当前进程/线程数量 18:当前在此 cgroup 中运行的数量

4.5. 通用控制器文件(所有 cgroup 目录都会包含)

文件名 用途说明 示例值说明
cgroup.procs 包含在该 cgroup 中的进程 PID 1234\n5678
cgroup.threads 包含线程 ID(TID) 1234\n5678(不同于 PID)
cgroup.controllers 当前节点支持的 controller 列表 cpu memory io pids
cgroup.subtree_control 子 cgroup 可继承的 controller 设置 +cpu +memory +io(必须手动 echo 设置)
cgroup.stat cgroup 统计信息 nr_descendants=3 nr_dying_descendants=0
cgroup.events 当前 cgroup 状态事件布尔值 populated 1 memory.events oom=0

4.6. 高阶行为控制(常见于 systemd 管理或进程终止场景)

文件名 用途说明 示例值说明
cgroup.freeze 是否冻结此 cgroup 中所有进程(0=运行,1=冻结) 0:未冻结
cgroup.kill 向所有进程发送 SIGKILL,强制终止 (执行 echo 1 > cgroup.kill
cgroup.type 当前 cgroup 类型 domain / threaded / domain threaded

5. Koordinator vs Volcano in cgroup v2 支持能力对比表

KoordinatorVolcano是常用的在服务混布和调度方面的开源调度组件,以下是 Koordinator vs Volcano 在 cgroup v2 层面对 Pod 资源隔离增强能力的对比表格,从四大类资源(CPU、内存、IO、网络)出发,列出各自支持的能力、作用机制和相关的 cgroup v2 文件名。

类别 能力 说明 Koordinator Volcano 使用的 cgroup v2 文件
CPU cpu.weight 调整调度优先级,高权重获得更多 CPU 时间片 cpu.weight
cpu.max 限速 限制低优 pod 最大可用 CPU 带宽 cpu.max
动态 CPU Throttle 根据压力指标自动调整低优 CPU 限速 ✅(PSI 感知) cpu.max, cpu.pressure
PSI 感知调度 根据 cpu.pressure 控制 pod 的调度去向 cpu.pressure
NUMA / CPU 绑核 结合 Topology 策略、QoS 实现高优绑核 非标准:cpuset.cpus(结合 CRI)
内存 memory.high 软限 超过此值将触发内核回收机制,避免高优被影响 memory.high
memory.low 保底 高优 pod 内存保底,不被回收 memory.low
OOM Group Kill 高优任务不被单独 kill,统一 OOM 策略 memory.events, cgroup.kill
PSI 感知调度 通过 memory.pressure 控制任务调度,避免拥塞节点 memory.pressure
IO io.max 带宽限速 精确限制某容器的磁盘读写速率(rbps/wbps) io.max
io.weight 权重 调整 IO 调度优先级 io.weight
IO PSI 感知调度 避免将 pod 调度到高 IO 压力节点 io.pressure
网络 网络速率控制(带宽) 非 cgroup v2 标准,通过 eBPF/TC/net_cls 配合实现 ✅(需扩展组件) 非标准:需 eBPF + tc + net_cls
网络 NUMA 感知调度 网络与计算资源拓扑感知,避免带宽竞争 非标准(TopologyHints)
通用 PSI 感知 综合调度参考 CPU/Memory/IO pressure *.pressure
Freeze / Kill 控制 在极端负载时暂停或终止低优任务 ✅(结合 memory.qos) cgroup.freeze, cgroup.kill
容器级 QoS 管控 每个容器细粒度配置 resource policy cpu.*, memory.*, io.*

6. 配置 Kubernetes 使用 cgroup v2

6.1. 版本要求

条件/组件 要求/版本
Linux 内核 ≥ 5.4(推荐 ≥ 5.10)
containerd ≥ 1.6,配置 SystemdCgroup = true
Kubernetes ≥ 1.24,建议 1.28+

6.2. 配置 Kubernetes 使用 cgroup v2

配置 kubelet 使用 systemd 驱动(匹配 cgroup v2)

  • kubelet 启动参数:
--cgroup-driver=systemd
  • containerd 的配置文件(/etc/containerd/config.toml):
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 
    SystemdCgroup = true
  • 重启 containerd:
systemctl restart containerd

或者

使用 kubeadm init 时建议显式指定:

kubeadm init --cgroup-driver=systemd ...

6.3. 验证 Kubernetes 是否运行在 cgroup v2

检查 cgroup 挂载类型:

mount | grep cgroup
# 输出如下则为cgroup v2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

验证 Pod 使用的是 cgroup v2 路径:

ps -eo pid,comm,cgroup | grep containerd-shim

输出中 cgroup 路径应以 /kubepods.slice/ 开头,无 cpu,cpuacct: 等逗号分隔子系统。

参考: