4. CPU 控制器详解:cpu.weight、cpu.max、cpu.stat 的配置与监控
Cgroup v2 的 CPU 控制器是容器运行时容量运维的核心组件,它通过三个关键接口文件实现 CPU 资源的分配、限制与监控。本章将深入解析 cpu.weight(权重分配)、cpu.max(硬限制)和 cpu.stat(状态监控)的工作原理、配置方法及运维实践。
4.1 CPU 控制器架构概览
在 Cgroup v2 中,CPU 控制器采用“权重 + 上限”的双层模型:权重决定竞争时的比例分配,上限则提供的资源天花板。下图展示了 CPU 控制器的核心架构与数据流。
4.2 cpu.weight:权重分配机制
cpu.weight 控制组之间 CPU 时间的相对比例,仅在 CPU 资源竞争时生效。默认值为 100,取值范围 1-10000。
4.2.1 权重分配原理
当多个 cgroup 同时争用 CPU 时,调度器按权重比例分配 CPU 时间。计算公式如下:
cgroup_i 的 CPU 份额 = (weight_i) / (所有活跃 cgroup 的 weight 之和) × 可用 CPU 时间
关键理解:权重是相对值而非值。如果只有一个 cgroup 活跃,即使 weight=1 也能使用全部 CPU;当多个 cgroup 竞争时,权重比例决定分配。
4.2.2 权重配置示例
以下示例展示如何为两个容器设置不同的 CPU 权重:
# 容器 A:高优先级(weight=200)
echo 200 > /sys/fs/cgroup/system.slice/docker-containerA.scope/cpu.weight
# 容器 B:低优先级(weight=50)
echo 50 > /sys/fs/cgroup/system.slice/docker-containerB.scope/cpu.weight
# 验证配置
cat /sys/fs/cgroup/system.slice/docker-containerA.scope/cpu.weight
cat /sys/fs/cgroup/system.slice/docker-containerB.scope/cpu.weight
当两个容器同时满载运行时,CPU 分配比例为 200:50 = 4:1,即容器 A 获得约 80% 的 CPU 时间,容器 B 获得约 20%。
4.2.3 权重与 CPU 数量的关系
| 权重值 | 含义 | 典型场景 |
|---|---|---|
| 1 | 最低优先级,仅当无竞争时获得 CPU | 后台日志处理、数据备份 |
| 100 | 默认权重,基线优先级 | 普通业务容器 |
| 500 | 高优先级,获得 5 倍于默认的份额 | 核心 API 服务、实时处理 |
| 1000 | 极高优先级,适合关键控制面组件 | Kubernetes 控制面、etcd |
| 10000 | 最大权重,几乎独占竞争资源 | 紧急恢复、关键监控代理 |
4.3 cpu.max:硬限制配置
cpu.max 以“配额/周期”格式设置 CPU 使用的上限,格式为 $quota $period。默认值为 max 100000(无限制)。
4.3.1 配额与周期详解
周期(period)默认为 100000μs(100ms),配额(quota)表示在每个周期内允许使用的 CPU 时间。配额值可以大于周期值,表示可以使用超过 1 个 CPU 核心。
| 配置值 | 含义 | 等效 CPU 核心数 |
|---|---|---|
max 100000 |
无限制 | 所有可用核心 |
50000 100000 |
每 100ms 最多使用 50ms CPU | 0.5 核心 |
100000 100000 |
每 100ms 最多使用 100ms CPU | 1 核心 |
200000 100000 |
每 100ms 最多使用 200ms CPU | 2 核心 |
250000 100000 |
每 100ms 最多使用 250ms CPU | 2.5 核心 |
4.3.2 配置示例与验证
# 限制容器使用 1.5 个 CPU 核心
echo "150000 100000" > /sys/fs/cgroup/system.slice/docker-container.scope/cpu.max
# 验证配置
cat /sys/fs/cgroup/system.slice/docker-container.scope/cpu.max
# 输出: 150000 100000
# 移除限制(设置为无限制)
echo "max 100000" > /sys/fs/cgroup/system.slice/docker-container.scope/cpu.max
运维警告:设置过小的配额(如
10000 100000,即 0.1 核心)可能导致容器频繁被节流(throttled),引发延迟敏感型应用的性能抖动。建议结合 cpu.stat 监控节流情况。
4.4 cpu.stat:状态监控与诊断
cpu.stat 文件提供 CPU 使用和节流的关键统计信息,是容量运维的核心监控数据源。
4.4.1 关键字段解读
| 字段名 | 单位 | 含义 | 运维关注点 |
|---|---|---|---|
usage_usec |
微秒 | 该 cgroup 累计使用的 CPU 时间 | 计算 CPU 使用率的基础 |
user_usec |
微秒 | 用户态累计 CPU 时间 | 区分用户态/内核态开销 |
system_usec |
微秒 | 内核态累计 CPU 时间 | 系统调用密集度判断 |
nr_periods |
次数 | 经过的调度周期总数 | 监控周期基数 |
nr_throttled |
次数 | 被节流的周期数 | 核心指标:节流频率 |
throttled_usec |
微秒 | 累计被节流的总时间 | 核心指标:节流严重程度 |
4.4.2 监控与诊断实践
以下脚本展示如何实时监控 CPU 节流情况:
#!/bin/bash
# cpu_throttle_monitor.sh - 监控容器 CPU 节流
CGROUP_PATH="/sys/fs/cgroup/system.slice/docker-container.scope"
INTERVAL=5
echo "监控 CPU 节流情况(每 ${INTERVAL} 秒)..."
echo "时间戳 | 使用率(%) | 节流次数 | 节流比例(%) | 节流时间(ms)"
while true; do
STAT=$(cat ${CGROUP_PATH}/cpu.stat)
MAX=$(cat ${CGROUP_PATH}/cpu.max | awk '{print $1}')
USAGE=$(echo "$STAT" | grep usage_usec | awk '{print $2}')
PERIODS=$(echo "$STAT" | grep nr_periods | awk '{print $2}')
THROTTLED=$(echo "$STAT" | grep nr_throttled | awk '{print $2}')
THROTTLED_USEC=$(echo "$STAT" | grep throttled_usec | awk '{print $2}')
# 计算使用率(基于最近间隔)
sleep ${INTERVAL}
STAT_NEW=$(cat ${CGROUP_PATH}/cpu.stat)
USAGE_NEW=$(echo "$STAT_NEW" | grep usage_usec | awk '{print $2}')
PERIODS_NEW=$(echo "$STAT_NEW" | grep nr_periods | awk '{print $2}')
THROTTLED_NEW=$(echo "$STAT_NEW" | grep nr_throttled | awk '{print $2}')
USAGE_DELTA=$(( (USAGE_NEW - USAGE) / 1000 )) # 转换为 ms
PERIODS_DELTA=$(( PERIODS_NEW - PERIODS ))
THROTTLED_DELTA=$(( THROTTLED_NEW - THROTTLED ))
# 计算 CPU 使用率(百分比)
CPU_PERCENT=$(echo "scale=2; ${USAGE_DELTA} / (${INTERVAL} * 1000) * 100" | bc)
# 计算节流比例
if [ ${PERIODS_DELTA} -gt 0 ]; then
THROTTLE_RATIO=$(echo "scale=2; ${THROTTLED_DELTA} / ${PERIODS_DELTA} * 100" | bc)
else
THROTTLE_RATIO="0.00"
fi
TIMESTAMP=$(date "+%H:%M:%S")
echo "${TIMESTAMP} | ${CPU_PERCENT}% | ${THROTTLED_DELTA} | ${THROTTLE_RATIO}% | $(( THROTTLED_USEC / 1000 ))ms"
done
4.5 权重与上限的协同策略
在实际运维中,cpu.weight 和 cpu.max 需要协同配置才能实现精细化的资源管理。下图展示了不同配置组合的效果。
4.6 运维最佳实践
容量运维黄金法则:
- 先设上限,再调权重:先用
cpu.max防止资源滥用,再用cpu.weight优化竞争分配。 - 监控节流比例:
nr_throttled / nr_periods超过 5% 时,考虑增加配额或优化应用。 - 避免过度限制:配额设置过低会导致频繁节流,增加上下文切换开销。
- 结合 NUMA 拓扑:在多 NUMA 节点环境中,配合
cpuset控制器使用效果更佳。 - 定期校准:业务负载变化后,重新评估权重和上限配置。
4.7 常见问题排查
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 容器 CPU 使用率低但延迟高 | 频繁节流(throttling) | 检查 cpu.stat 的 nr_throttled |
增加 cpu.max 配额 |
| 高优容器未获得预期资源 | 权重配置未生效或存在更高优任务 | 检查所有活跃 cgroup 的权重值 | 调整权重比例或使用 cpu.max 限制低优任务 |
| CPU 使用率波动剧烈 | 配额/周期设置不合理 | 分析 throttled_usec 时间分布 |
增大周期值(如 200000μs)平滑分配 |
设置 cpu.max 后无效果 |
CPU 控制器未启用 | 检查 /sys/fs/cgroup/cgroup.controllers |
向 cgroup.subtree_control 写入 +cpu |
重要提示:在 Kubernetes 环境中,
cpu.weight 对应 Pod 的 requests.cpu,cpu.max 对应 limits.cpu。理解底层映射关系有助于更精准地配置容器资源。