3. Cgroups CPU子系统:cgroups v1与v2概述、cpu.shares与cpu.weight、cpu.cfs_period_us与cpu.cfs_quota_us

CPU 子系统是 cgroups 中控制容器 CPU 资源分配的核心模块。理解 cgroups v1 与 v2 的架构差异、权重分配机制以及带宽控制参数,是进行容器 CPU 绑核与性能调优的基础。本节将系统梳理这些关键概念。

3.1 cgroups v1 与 v2 概述

cgroups(Control Groups)自 Linux 2.6.24 引入以来,经历了从 v1 到 v2 的重大演进。v1 采用多层级、多挂载点的树形结构,每个子系统独立挂载;v2 则统一为单层级树,所有子系统挂载在同一根目录下,解决了 v1 中进程在不同子系统间不一致的问题。

关键演进: v2 要求所有控制器(controller)必须挂载在同一个 cgroup 树中,且进程只能属于一个 cgroup 节点,避免了 v1 中进程可能同时属于多个不同层级 cgroup 导致的资源竞争与统计混乱。
对比维度 cgroups v1 cgroups v2
层级结构 多层级树,每个子系统独立挂载 单层级树,所有控制器统一挂载
进程归属 进程可在不同子系统属于不同 cgroup 进程只能属于一个 cgroup 节点
CPU 控制器 cpu、cpuacct 分离 cpu 控制器合并统计与限制
权重接口 cpu.shares cpu.weight
带宽控制 cpu.cfs_period_us + cpu.cfs_quota_us cpu.max(格式:quota period)
实时调度 cpu.rt_period_us + cpu.rt_runtime_us 暂不支持实时控制器
生产建议: 新部署的 Kubernetes 集群(v1.24+)推荐使用 cgroups v2,它提供了更一致的资源视图和更简洁的接口。Docker 从 20.10 版本起已默认支持 cgroups v2。
cgroups v1 与 v2 架构对比 cgroups v1(多层级树) cpu 子系统树 cpuacct 子系统树 memory 子系统树 blkio 子系统树 进程 P 跨树归属 cgroups v2(单层级树) 统一 cgroup 树 cpu + cpuacct 合并 memory 控制器 io 控制器 进程 P 唯一归属 v2 所有控制器挂载在同一个 cgroup 树中

3.2 cpu.shares 与 cpu.weight:CPU 权重分配

CPU 权重决定了多个 cgroup 在 CPU 资源竞争时的分配比例。v1 使用 cpu.shares,v2 使用 cpu.weight,两者本质都是相对权重,而非限制。

3.2.1 cpu.shares(cgroups v1)

cpu.shares 的默认值为 1024,取值范围为 2~262144。当多个 cgroup 中的进程同时争用 CPU 时,调度器按 shares 比例分配 CPU 时间。如果只有一个 cgroup 有进程运行,它可以占用全部 CPU 资源。

# 创建两个 cgroup 并设置不同的 shares
mkdir -p /sys/fs/cgroup/cpu/group_high /sys/fs/cgroup/cpu/group_low
echo 2048 > /sys/fs/cgroup/cpu/group_high/cpu.shares
echo 512  > /sys/fs/cgroup/cpu/group_low/cpu.shares

# 将进程 PID 加入对应 cgroup
echo $PID_HIGH > /sys/fs/cgroup/cpu/group_high/tasks
echo $PID_LOW  > /sys/fs/cgroup/cpu/group_low/tasks

# 此时 group_high 与 group_low 的 CPU 分配比例为 2048:512 = 4:1

3.2.2 cpu.weight(cgroups v2)

cpu.weight 的默认值为 100,取值范围为 1~10000。v2 使用线性权重模型,计算更直观。v2 还提供了 cpu.weight.nice 接口,允许通过 nice 值(-20~19)映射到权重。

# cgroups v2 设置权重
mkdir -p /sys/fs/cgroup/group_high /sys/fs/cgroup/group_low
echo 200 > /sys/fs/cgroup/group_high/cpu.weight
echo 50  > /sys/fs/cgroup/group_low/cpu.weight

# 将进程写入 cgroup.procs
echo $PID_HIGH > /sys/fs/cgroup/group_high/cgroup.procs
echo $PID_LOW  > /sys/fs/cgroup/group_low/cgroup.procs

# 分配比例 200:50 = 4:1
参数 所属版本 默认值 取值范围 权重模型
cpu.shares v1 1024 2 ~ 262144 相对比例
cpu.weight v2 100 1 ~ 10000 线性权重
cpu.weight.nice v2 0 -20 ~ 19 nice 映射
常见误区: cpu.shares 和 cpu.weight 不是 CPU 硬限制。当系统空闲时,低权重 cgroup 仍可使用全部 CPU。它们只在 CPU 争用时生效,属于“软保证”机制。

3.3 cpu.cfs_period_us 与 cpu.cfs_quota_us:CPU 带宽控制

CFS(Completely Fair Scheduler)带宽控制提供了 CPU 使用的硬限制。通过 cpu.cfs_period_us 和 cpu.cfs_quota_us 两个参数,可以精确限制一个 cgroup 在指定周期内最多使用的 CPU 时间。

3.3.1 参数含义

  • cpu.cfs_period_us:带宽控制周期,单位微秒(µs),默认 100000(100ms),取值范围 1000~1000000。
  • cpu.cfs_quota_us:在每个周期内允许使用的 CPU 时间,单位微秒(µs),默认 -1(不限制)。

通过这两个参数可以计算出 cgroup 能使用的 CPU 核心数上限:

CPU 核心数上限 = cpu.cfs_quota_us / cpu.cfs_period_us

示例:
  period = 100000 µs(100ms)
  quota  = 200000 µs(200ms)
  → 可使用 2 个 CPU 核心

  period = 100000 µs
  quota  =  50000 µs(50ms)
  → 可使用 0.5 个 CPU 核心

3.3.2 实际配置示例

# 限制 cgroup 最多使用 1.5 个 CPU 核心
echo 100000 > /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_period_us
echo 150000 > /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_quota_us

# 限制 cgroup 最多使用 4 个 CPU 核心
echo 100000 > /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_period_us
echo 400000 > /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_quota_us

# 取消限制(恢复为不限制)
echo -1 > /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_quota_us

3.3.3 cgroups v2 中的对应接口

在 cgroups v2 中,带宽控制通过 cpu.max 文件统一管理,格式为 $MAX $PERIOD:

# 限制最多使用 1.5 个 CPU 核心
echo "150000 100000" > /sys/fs/cgroup/mycontainer/cpu.max

# 取消限制
echo "max 100000" > /sys/fs/cgroup/mycontainer/cpu.max
CFS 带宽控制:period 与 quota 机制 周期 1 period = 100ms quota = 80ms 空闲 周期 2 period = 100ms quota = 100ms(满) 周期 3 period = 100ms 60ms 空闲 40ms 周期 4 period = 100ms quota = 80ms 带宽控制关键点 • 每个周期内,cgroup 最多使用 quota 微秒的 CPU 时间 • 超过 quota 后,进程会被节流(throttled),直到下一个周期开始 • quota / period = 可使用的 CPU 核心数上限(硬限制)

3.4 权重与带宽的协同使用

在实际容器编排中,权重和带宽控制通常配合使用:

  • 带宽控制(硬限制):通过 cfs_quota_us 设定容器 CPU 使用上限,防止单个容器抢占过多资源。
  • 权重分配(软保证):通过 cpu.shares 或 cpu.weight 设定容器在 CPU 争用时的优先级。
Kubernetes 实践:
  • spec.containers[].resources.limits.cpu → 映射为 cpu.cfs_quota_us / cpu.cfs_period_us
  • spec.containers[].resources.requests.cpu → 映射为 cpu.shares(v1)或 cpu.weight(v2)
例如:limits.cpu=2, requests.cpu=1 表示容器最多使用 2 核,但保证至少获得 1 核的权重。

3.5 性能调优注意事项

场景 推荐配置 说明
延迟敏感型应用 quota 略高于实际需求 避免频繁节流导致延迟抖动
批处理任务 quota 精确匹配需求 充分利用资源,避免浪费
混部场景 权重差异化 + 带宽限制 高优服务高权重,低优任务低权重并设硬限
period 选择 默认 100ms 通常足够 过小(<10ms)增加调度开销;过大(>500ms)降低响应性
调优建议: 对于延迟敏感型容器,建议将 cpu.cfs_period_us 设置为 10000µs(10ms),配合适当的 quota 值,可以在毫秒级粒度上控制 CPU 分配,减少突发流量下的调度延迟。