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 策略:

CPU Manager 策略选择决策流程 工作负载评估 延迟敏感? none 策略 高资源利用率,允许核心共享 检查 QoS 等级 Guaranteed? none 策略(回退) static 策略

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 构建任务短暂且多样,共享核心更经济