3、cgroup CPU 子系统基础:核心文件解析

在容器化环境中,CFS(Completely Fair Scheduler)通过 cgroup CPU 子系统的四个关键文件实现 CPU 资源的分配与限制。理解 cpu.shares、cpu.cfs_period_us、cpu.cfs_quota_us 和 cpu.stat 是配置容器 CPU 组调度的基础。本节将逐一解析每个文件的作用、参数含义及典型配置。

3.1 文件概览与功能对比

下表列出了 cgroup CPU 子系统的核心文件及其在 CFS 调度中的角色:

文件名 作用域 控制粒度 默认值 典型场景
cpu.shares 相对权重 CPU 时间比例 1024 多容器按比例分配 CPU
cpu.cfs_period_us 周期长度 微秒(μs) 100000 定义配额计算的时间窗口
cpu.cfs_quota_us 硬性上限 微秒(μs) -1(无限制) 限制容器最大 CPU 使用量
cpu.stat 统计信息 只读 — 监控调度延迟与限流情况
关键概念区分:cpu.shares 仅在 CPU 资源竞争时生效,属于“软限制”;cpu.cfs_quota_us 无论是否竞争都强制生效,属于“硬限制”。两者配合使用可实现精细化的 CPU 资源管控。

3.2 cpu.shares —— 相对权重分配

cpu.shares 定义了 cgroup 在 CPU 时间竞争中的相对权重。当多个 cgroup 同时需要 CPU 时,调度器按 shares 值的比例分配 CPU 时间。该值是一个整数,默认值为 1024。

工作原理:

  • 假设两个 cgroup A 和 B,shares 分别为 1024 和 2048。
  • 当两者都满负荷运行时,A 获得约 1/3 的 CPU 时间,B 获得约 2/3。
  • 如果只有一个 cgroup 活跃,它可以占用全部 CPU 资源(不受 shares 限制)。
配置示例:为容器设置 shares 为 2048,使其在竞争时获得两倍于默认容器的 CPU 时间。
# 设置 cpu.shares 为 2048
echo 2048 > /sys/fs/cgroup/cpu/docker/container1/cpu.shares

# 验证当前值
cat /sys/fs/cgroup/cpu/docker/container1/cpu.shares
# 输出:2048
cpu.shares 权重分配示意图 容器 A shares = 1024 容器 B shares = 2048 CFS 调度器 竞争时 CPU 分配比例:容器 A 约 33% ,容器 B 约 66% 空闲时任一容器均可使用 100% CPU

3.3 cpu.cfs_period_us 与 cpu.cfs_quota_us —— 硬性上限控制

这两个文件配合使用,实现 CFS 配额机制,对 cgroup 的 CPU 使用量进行硬性限制。

  • cpu.cfs_period_us:一个调度周期的时间长度,单位为微秒(μs),默认值 100000(即 100ms)。
  • cpu.cfs_quota_us:在每个周期内,cgroup 允许使用的最大 CPU 时间,单位为微秒(μs)。默认值 -1 表示无限制。

配额计算方式:

  • 有效 CPU 核心数 = cpu.cfs_quota_us / cpu.cfs_period_us
  • 例如:quota = 200000,period = 100000,则限制为 2 个 CPU 核心。
  • 例如:quota = 50000,period = 100000,则限制为 0.5 个 CPU 核心。
注意事项:当 cpu.cfs_quota_us 设置过小(如小于一个调度 tick)时,可能导致容器频繁被限流,引发调度延迟。建议生产环境中 quota 值至少为 period 的 10%。
CFS 配额周期示意图(period / quota) 时间 周期 1 period = 100ms 周期 2 period = 100ms 周期 3 period = 100ms quota = 50ms (限制 0.5 核) 每个周期内,容器最多使用 quota 指定的 CPU 时间,超出的部分将被限流 quota / period = 有效 CPU 核心数(例如 50ms / 100ms = 0.5 核)

3.4 cpu.stat —— 调度统计与限流监控

cpu.stat 是一个只读文件,提供 cgroup 的 CPU 调度统计信息,用于监控容器是否被限流以及调度延迟情况。

文件内容示例:

nr_periods 1000
nr_throttled 45
throttled_time 12345678
nr_bursts 0
burst_time 0

字段含义:

字段名 类型 说明
nr_periods 整数 自 cgroup 创建以来经历的调度周期总数
nr_throttled 整数 被限流的周期数(即 CPU 使用超过 quota 的周期)
throttled_time 纳秒 累计被限流的总时间(纳秒)
nr_bursts 整数 发生突发(burst)的次数(需内核支持 CPU burst 特性)
burst_time 纳秒 累计突发使用的时间(纳秒)
监控指标解读:
  • 限流率 = nr_throttled / nr_periods:反映容器被限流的频率。限流率过高(如 > 5%)说明 quota 设置偏小,需考虑扩容。
  • throttled_time:累计限流时间持续增长,表明容器频繁等待 CPU 资源,可能影响业务延迟。
  • nr_bursts / burst_time:如果 burst 值持续增长,说明容器在利用突发能力弥补短期性能缺口。
cpu.stat 限流监控流程 容器进程 CFS 调度器 超 quota? 限流 nr_throttled++ 正常调度 nr_periods++

3.5 综合配置案例

以下是一个完整的 cgroup CPU 子系统配置示例,展示如何同时使用 shares、quota 和 period 控制容器 CPU 资源:

# 创建 cgroup 目录
mkdir -p /sys/fs/cgroup/cpu/demo_container

# 设置相对权重(竞争时获得 2 倍默认权重)
echo 2048 > /sys/fs/cgroup/cpu/demo_container/cpu.shares

# 设置调度周期为 100ms(默认值)
echo 100000 > /sys/fs/cgroup/cpu/demo_container/cpu.cfs_period_us

# 设置配额为 150ms(限制为 1.5 个 CPU 核心)
echo 150000 > /sys/fs/cgroup/cpu/demo_container/cpu.cfs_quota_us

# 将进程 PID 加入 cgroup
echo 12345 > /sys/fs/cgroup/cpu/demo_container/tasks

# 查看统计信息
cat /sys/fs/cgroup/cpu/demo_container/cpu.stat
最佳实践:在容器化环境中,建议将 cpu.cfs_period_us 保持为默认值 100ms,仅调整 cpu.cfs_quota_us 和 cpu.shares。频繁修改 period 值可能导致调度器行为异常,且对大多数应用场景无额外收益。