1. cgroup v2 概述:诞生背景、核心差异与统一层级树设计

1.1 诞生背景:为什么需要 cgroup v2?

cgroup(Control Groups)是 Linux 内核提供的一种资源隔离与管控机制,自 2007 年合并入主线以来,cgroup v1 在容器、虚拟化、系统资源管理等场景中得到了广泛应用。然而,随着生产环境对资源观测精度、安全隔离性和运维复杂度的要求不断提高,v1 的设计缺陷逐渐暴露,成为可观测性与延迟分析的瓶颈。

v1 核心痛点: 多层级树碎片化导致资源视图割裂;不同子系统(如 cpu、memory、blkio)挂载到独立层级树,运维人员需要同时维护多棵“森林”,难以在统一视图中关联 CPU 与内存的延迟事件。

cgroup v2 自 Linux 4.5 开始引入,并在 4.15 之后逐步稳定。它并非简单的增量升级,而是对资源管控模型的重构,核心目标包括:

  • 统一层级树:所有子系统挂载到同一棵层级树,消除多树并行带来的管理混乱。
  • 安全增强:限制非特权用户对 cgroup 的写入权限,减少攻击面。
  • 资源压力观测:引入 PSI(Pressure Stall Information)机制,直接输出 CPU、内存、IO 的延迟水位。
  • 线程级管理废弃:cgroup v2 只管理进程,不再支持线程级迁移,简化内核路径。

1.2 核心差异:v1 与 v2 的对比

下表从架构、资源模型、可观测性、安全与兼容性五个维度,系统对比 v1 与 v2 的核心差异:

对比维度 cgroup v1 cgroup v2
层级树 多棵独立树,每子系统一棵 单棵统一层级树,所有子系统共享
资源控制模型 各子系统独立配置,无全局一致性 统一接口,资源分配与限制在同一文件系统下
可观测性 无原生压力指标,依赖外部工具 内建 PSI 指标,直接输出延迟水位
线程管理 支持线程级迁移,复杂度高 仅管理进程级,简化内核路径
安全模型 非特权用户可写入部分控制文件 严格限制非特权写入,需 delegation 授权
兼容性 默认挂载方式,广泛支持 需内核启动参数 cgroup_no_v1=all 或 systemd 统一管理
SRE 视角: 在延迟敏感型业务中,v2 的 PSI 指标可以直接暴露 CPU 和内存的“等待时间占比”,这是 v1 无法原生提供的。迁移到 v2 后,延迟水位的观测精度可以从秒级提升到毫秒级。

1.3 统一层级树设计理念

统一层级树(Unified Hierarchy)是 cgroup v2 最核心的设计变更。它将所有资源控制器(Controller)挂载到同一棵树的同一个挂载点(通常为 /sys/fs/cgroup),每个 cgroup 目录下同时包含 cpu、memory、io 等所有子系统的控制文件。

这种设计的核心理念包括:

  • 资源视图一致:一个进程组的所有资源限制在同一目录下配置,避免 v1 中跨树查找的混乱。
  • 内核对齐:内核在遍历 cgroup 时只需遍历一棵树,减少锁竞争和路径开销。
  • 子节点继承:子 cgroup 自动继承父节点的资源上限,形成清晰的资源配额链。
  • 无内部进程:非根 cgroup 只能包含子 cgroup 或进程,不能同时包含两者,避免资源统计歧义。

下图展示了统一层级树的结构与资源控制器的分布关系:

cgroup v2 统一层级树结构 /sys/fs/cgroup (根) system.slice user.slice machine.slice docker-abc.scope sshd.service user-1000.slice libvirt-qemu 每个 cgroup 目录下包含的资源控制器文件: cpu.max cpu.weight memory.max memory.current io.max io.weight pids.max 所有控制器在同一目录下,无需跨树查找;子节点自动继承父节点资源上限。 统一层级树:所有子系统挂载到同一棵树,每个节点同时管控 CPU、内存、IO、PIDs

1.4 无内部进程规则与资源继承

统一层级树引入了一个关键约束:非根 cgroup 不能同时包含子 cgroup 和进程。这意味着:

  • 如果一个 cgroup 目录下有子目录,则它自身不能附加任何进程。
  • 所有进程必须位于叶子节点(leaf node)中。
  • 资源限制从根到叶子逐层继承,父节点的上限是子节点的硬天花板。
延迟观测影响: 无内部进程规则保证了资源统计的确定性。在 v1 中,一个非叶子 cgroup 同时包含进程和子 cgroup 时,资源使用量会被重复计算,导致延迟分析出现偏差。v2 消除了这一歧义,使得 PSI 指标可以精确反映叶子节点的真实压力。

下图对比了 v1 的多树碎片化与 v2 的统一树设计:

v1 多树 vs v2 统一树 cgroup v1:多棵独立树 cpu 树 memory 树 blkio 树 pids 树 每棵树独立挂载点 进程需加入多棵树 资源视图割裂 运维复杂度高 cgroup v2:统一层级树 /sys/fs/cgroup(单一挂载点) cpu memory io pids 所有控制器在同一目录 进程只需加入一棵树 资源视图统一

1.5 从 v1 迁移到 v2 的注意事项

对于正在运行 v1 的生产环境,迁移到 v2 需要关注以下关键点:

  • 内核版本:建议使用 Linux 5.2+,PSI 和 io 控制器在 5.0+ 已稳定。
  • systemd 版本:systemd v242+ 默认使用 cgroup v2,可通过 systemd.unified_cgroup_hierarchy=1 启用。
  • 容器运行时:Docker 20.10+、containerd 1.5+、Podman 3.0+ 已原生支持 v2。
  • 监控工具:确保 cadvisor、Prometheus node_exporter 等工具支持 v2 的指标路径。
  • 回退方案:保留 v1 混合模式(hybrid mode)作为过渡,但混合模式会降低 PSI 的精度。
延迟观测最佳实践: 迁移完成后,立即验证 /proc/pressure/cpu、/proc/pressure/memory、/proc/pressure/io 三个文件是否可读。这些文件是 v2 延迟水位的直接数据源,后续章节将深入解析其格式与阈值设定。