3. CPU Manager Policy 概述:static 与 none 策略的差异及适用场景
CPU Manager 是 kubelet 中负责 CPU 资源分配的核心组件,其策略直接决定了 Pod 中容器能够获得的 CPU 拓扑与性能隔离程度。Kubernetes 默认提供两种内置策略:none 和 static。理解这两种策略的差异,是进行 CPU 敏感型工作负载性能调优的第一步。
3.1 策略核心差异对比
下表从分配粒度、CPU 亲和性、性能隔离性、适用负载类型等维度,对两种策略进行系统性对比:
| 对比维度 | none 策略 | static 策略 |
|---|---|---|
| 分配粒度 | 仅保证 CPU 份额(CFS quota),不绑定物理核心 | 为 Guaranteed QoS Pod 独占物理核心(CPU pinning) |
| CPU 亲和性 | 无硬亲和性,调度器可在任意核心间迁移 | 强亲和性,容器进程被绑定到特定核心集 |
| 性能隔离性 | 低,受同节点其他 Pod 的 CPU 争抢影响明显 | 高,独占核心消除“吵闹邻居”效应 |
| 上下文切换 | 频繁,核心迁移导致缓存污染和切换开销 | 极低,进程长期驻留同一核心,L1/L2 缓存命中率高 |
| CPU 拓扑感知 | 不感知 NUMA/NUMA 节点,可能跨 socket 分配 | 支持拓扑管理器协调,可优化 NUMA 亲和性 |
| 适用负载 | 通用型、微服务、批处理、对延迟不敏感的任务 | 延迟敏感型、实时计算、DPDK、NFV、高频交易 |
| 资源利用率 | 高,核心可被多个 Pod 共享 | 较低,独占核心在空闲时无法被其他 Pod 复用 |
3.2 none 策略详解
none 策略是 kubelet 的默认策略,其行为与传统的 Linux CFS(Completely Fair Scheduler)完全一致。kubelet 仅通过 cgroups 中的 cpu.shares 和 cpu.cfs_quota_us 来限制容器的 CPU 使用上限,但不对容器进程绑定任何特定的物理 CPU 核心。
关键行为特征:
- 所有容器共享节点上的所有 CPU 核心,内核调度器根据权重动态分配时间片。
- 容器进程可以在不同核心间自由迁移,迁移频率取决于系统负载和调度决策。
- 对于
requests和limits不相等或非整数的 Pod,none 策略是唯一可用的策略。
none 策略的优势在于资源利用率高,适合大多数无状态微服务和批处理作业。但其代价是性能波动较大,当节点上存在 CPU 密集型 Pod 时,延迟敏感型应用的尾延迟会显著恶化。
3.3 static 策略详解
static 策略专为需要 CPU 性能保障的 Guaranteed QoS Pod 设计。当 Pod 满足以下条件时,kubelet 会为其分配一组独占的物理 CPU 核心:
- Pod 中所有容器的
cpu.requests等于cpu.limits。 - CPU 资源值必须为整数(如 1、2、4),不支持小数。
- Pod 的 QoS 等级为 Guaranteed。
static 策略的核心分配流程如下:
1. kubelet 启动时扫描节点 CPU 拓扑,将核心分为“预留池”和“可分配池”。
2. 预留池(--reserved-cpus 或 system-reserved/kube-reserved)用于系统进程和 kubelet 组件。
3. 当符合条件的 Guaranteed Pod 被调度到节点时,kubelet 从可分配池中选取整数个核心。
4. 通过 cpuset cgroup 将选中的核心绑定到容器内的所有进程。
5. 容器进程从此只能在这些核心上运行,其他 Pod 的进程无法使用这些核心。
性能收益来源:static 策略消除了 CPU 核心迁移带来的缓存失效开销(cache miss),同时避免了同节点其他 Pod 的 CPU 争抢。对于 L1/L2 缓存敏感型应用(如 Redis、Memcached、实时音视频编解码),性能提升可达 20%–50%。
3.4 策略选择决策流程
下图展示了在实际集群中如何根据工作负载特征选择 CPU Manager 策略:
3.5 配置示例与验证
在 kubelet 配置文件中启用 static 策略:
# /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cpuManagerPolicy: "static" # 可选 "none" 或 "static"
cpuManagerReconcilePeriod: "10s" # 策略协调周期
topologyManagerPolicy: "best-effort" # 可选配合拓扑管理器
reservedSystemCPUs: "0,1" # 预留前两个核心给系统
验证 static 策略是否生效:
# 查看 Pod 的 cpuset 分配
kubectl exec -it <pod-name> -- cat /sys/fs/cgroup/cpuset/cpuset.cpus
# 预期输出示例:显示绑定的核心列表
2-3
# 查看 kubelet 日志确认策略分配
journalctl -u kubelet | grep "cpuManager"
# 输出示例:I0912 10:15:30.123456 12345 cpu_manager.go:456]
# [cpumanager] static policy: assigned container <container-id>
# to cpuset [2-3]
注意事项:
- 启用 static 策略前,必须预留足够的 CPU 核心给系统进程(建议至少预留 1-2 个核心)。
- static 策略仅对整数 CPU 请求的 Guaranteed Pod 生效,非整数或 Burstable Pod 仍使用 none 策略行为。
- 在启用 Topology Manager 时,static 策略可以与 NUMA 亲和性策略协同工作,进一步优化内存访问延迟。
3.6 适用场景总结
根据实际生产环境经验,以下场景推荐使用对应的策略:
| 场景类型 | 推荐策略 | 原因说明 |
|---|---|---|
| 通用 Web 服务、API 网关 | none | 请求量波动大,核心共享可提高整体吞吐 |
| Redis / Memcached 缓存 | static | 缓存命中率对 CPU 亲和性极度敏感 |
| 实时音视频转码 | static | 需要稳定的 CPU 周期保障帧率 |
| 大数据批处理(Spark/MapReduce) | none | 任务可并行化,核心迁移影响可忽略 |
| DPDK / NFV 网络功能 | static | 用户态驱动需要独占核心避免中断干扰 |
| CI/CD 构建节点 | none | 构建任务短暂且多样,共享核心更经济 |