3. CPU 资源配额实战:Requests/Limits 配置策略与 CPU Throttling 分析
3.1 CPU Requests 与 Limits 核心概念
在 Kubernetes 中,CPU 资源配额通过 requests 和 limits 两个字段控制。理解两者的差异是避免性能抖动和资源浪费的前提。
| 属性 | Requests(保证量) | Limits(上限) |
|---|---|---|
| 调度依据 | 调度器根据节点剩余可分配资源决定 Pod 放置位置 | 不参与调度决策 |
| CPU 份额权重 | CFS 调度器按 requests 比例分配 CPU 时间片 | 不影响权重,仅限制突发上限 |
| 是否可超卖 | 节点总 requests 可超过节点容量(超卖) | 节点总 limits 可超过节点容量 |
| CPU Throttling | 不直接触发节流 | 超过 limits 时强制节流(CFS quota) |
| 典型配置策略 | 设为稳态负载基线 | 设为容忍突发峰值上限 |
最佳实践:生产环境建议始终设置 CPU requests,避免因未设置导致调度器低估负载。对于延迟敏感型工作负载,requests 应等于 limits,消除 CPU 节流风险。
3.2 CPU Throttling 现象与根因分析
CPU Throttling 是指容器在 CFS(Completely Fair Scheduler)配额用尽后被迫等待下一个周期的现象。高节流率直接导致请求延迟增加、吞吐量下降。
3.2.1 节流产生机制
- Kubelet 为每个容器创建 cgroup,设置
cpu.cfs_quota_us和cpu.cfs_period_us。 - 默认周期
cfs_period_us= 100ms(100000μs)。 - 若 limits = 2 核,则
cfs_quota_us= 200000μs,容器每 100ms 最多使用 200ms CPU 时间。 - 当容器在周期内用完配额,剩余时间被强制节流,直到下一个周期重置。
常见误区:很多团队认为设置较高的 limits 就能避免节流,但忽略了 CFS 周期粒度。即使平均 CPU 使用率低于 limits,短时间内的微突发也可能在单个周期内耗尽配额,导致毫秒级节流。
3.2.2 节流检测方法
# 通过 cgroup 直接查看节流统计
cat /sys/fs/cgroup/cpu/kubepods/burstable/pod<pod-uid>/<container-id>/cpu.stat
# 输出示例
nr_periods 124567
nr_throttled 8923
throttled_time 4567890123
# 节流率 = nr_throttled / nr_periods = 8923 / 124567 ≈ 7.16%
使用 kubectl top pod 或 Prometheus 指标 container_cpu_cfs_throttled_seconds_total 可进行集群级监控。
3.3 CPU Requests/Limits 配置策略
3.3.1 三种典型配置模式
| 模式 | Requests | Limits | 适用场景 |
|---|---|---|---|
| Guaranteed(保障型) | = Limits | = Requests | 延迟敏感、数据库、核心中间件 |
| Burstable(突发型) | < Limits | > Requests | Web 服务、批处理、有波峰负载 |
| BestEffort(尽力型) | 未设置 | 未设置 | 低优先级、可被驱逐的离线任务 |
3.3.2 基于性能数据的配置方法
- 采集基线:使用 Prometheus 或 VPA 分析过去 7 天 P50/P95/P99 CPU 使用率。
- 设置 requests:取 P50 或 P70 值,确保调度器预留足够资源。
- 设置 limits:取 P95 或 P99 值,或设置为 requests 的 1.5~2 倍。
- 验证节流率:目标 nr_throttled / nr_periods < 1%。若超过 5%,需调整 limits 或优化代码。
案例:某 Java 微服务 P50 CPU = 0.8 核,P99 = 1.6 核。配置 requests: 800m,limits: 1600m。运行后节流率 3.2%,将 limits 提升至 2000m 后节流率降至 0.4%,P99 延迟降低 22%。
3.4 CPU Manager 与拓扑感知调度
CPU Manager 是 kubelet 组件,负责管理 Guaranteed Pod 的 CPU 亲和性。拓扑感知调度则让调度器感知 NUMA 节点拓扑,避免跨 NUMA 访问导致的内存延迟。
3.4.1 CPU Manager 策略对比
| 策略 | 行为 | 适用场景 |
|---|---|---|
| none | 默认策略,不绑定固定 CPU,允许任意调度 | 非性能敏感型工作负载 |
| static | 为整数核 Guaranteed Pod 分配独占 CPU 核心 | 高吞吐、低延迟、DPDK、实时应用 |
3.4.2 拓扑感知调度(Topology Manager)
Topology Manager 与 CPU Manager、Device Manager 协同,确保 Pod 的 CPU、内存、设备分配在同一个 NUMA 节点上,减少跨 NUMA 访问开销。
# kubelet 配置示例(kubelet-config.yaml)
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cpuManagerPolicy: "static"
topologyManagerPolicy: "single-numa-node"
topologyManagerScope: "pod"
reservedSystemCPUs: "0-1" # 预留 2 个核给系统进程
注意事项:
- static 策略仅对 整数核 requests = limits 的 Guaranteed Pod 生效。
- 启用 topologyManagerPolicy: single-numa-node 后,若节点无法满足 NUMA 对齐,Pod 将处于
TopologyAffinity错误状态。 - 预留 CPU(reservedSystemCPUs)必须与 kubelet 命令行
--system-reserved保持一致。
3.5 CPU 资源配额与拓扑感知架构图
3.6 实战配置清单与验证步骤
3.6.1 配置清单
apiVersion: v1
kind: Pod
metadata:
name: cpu-performance-demo
spec:
containers:
- name: app
image: myapp:latest
resources:
requests:
cpu: "2" # 保证 2 核
limits:
cpu: "2" # 上限 2 核,Guaranteed 模式
args:
- --cpus=2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
3.6.2 验证步骤
- 检查 Pod 状态:
kubectl describe pod cpu-performance-demo确认 QoS 为 Guaranteed。 - 验证 CPU 绑定:进入容器执行
cat /sys/fs/cgroup/cpuset/cpuset.cpus查看绑定的物理核心。 - 监控节流:使用
kubectl exec -- cat /sys/fs/cgroup/cpu/cpu.stat计算节流率。 - 延迟测试:使用 wrk 或 hey 施加负载,对比 P99 延迟与节流率变化。
性能调优检查清单:
- 所有生产 Pod 必须设置 CPU requests,避免 BestEffort 导致资源争抢。
- 延迟敏感型服务使用 Guaranteed QoS,requests = limits。
- 启用 CPU Manager static 策略前,确认节点预留了足够的系统 CPU。
- 多 NUMA 节点环境启用 Topology Manager,策略设为 single-numa-node。
- 定期监控 nr_throttled 指标,节流率超过 5% 时立即调整 limits 或优化代码。