2. 资源模型与度量基础

自动扩缩容的每一次决策,最终都要落到“当前用了多少、目标是多少、还能加多少”这三个数字上。如果资源模型和度量口径不统一,HPA 的阈值再合理也会得出错误结论。本节先把 Kubernetes 的资源语义、QoS 分级、利用率算法和指标来源讲清楚,为后续 HPA、VPA、Cluster Autoscaler 的配置打下可计算的基础。

requests 与 limits:调度依据与运行边界

容器资源声明中,requests 和 limits 承担两种完全不同的职责。requests 是调度器(kube-scheduler)做放置决策的依据:它把 Pod 的 requests 累加到节点的已分配资源上,只有剩余可分配量足够时才会调度。因此 requests 决定“能不能被排上去”,而不是“实际会用多少”。limits 则是 kubelet 与内核 cgroup 施加的运行边界:CPU 超过 limit 会被 CFS 限流(throttling),内存超过 limit 会触发 OOM Kill。

CPU 是可压缩资源,超限表现为变慢而非被杀;内存是不可压缩资源,超限直接终止容器。这一差异决定了扩缩容策略:CPU 型服务可以适度让 requests 小于 limits 以提高装箱率,内存型服务则应尽量让 requests 接近 limits,避免节点内存超卖导致连锁 OOM。

resources:
  requests:
    cpu: "500m"      # 0.5 核,调度依据
    memory: "512Mi"
  limits:
    cpu: "1000m"     # 1 核,CFS 限流上限
    memory: "1Gi"    # 超限触发 OOM Kill

QoS 分级:三种资源保障等级

Kubernetes 根据 requests 与 limits 的关系自动为 Pod 分配 QoS 等级,它直接影响节点资源紧张时的驱逐顺序:BestEffort 最先被驱逐,Burstable 次之,Guaranteed 最后。判定规则如下:

  • Guaranteed:所有容器都设置了 CPU 和内存的 requests 与 limits,且两者相等。适合核心数据库、关键网关。
  • Burstable:至少一个容器设置了 requests 或 limits,但不满足 Guaranteed 条件。绝大多数业务服务属于此类。
  • BestEffort:所有容器都没有设置任何 requests 和 limits。仅适合可随时中断的批处理。

需要特别注意的是,只要有一个容器缺少 requests 或 limits,整个 Pod 就降级为 Burstable。因此为 sidecar、init 容器补齐资源声明,是保证 QoS 等级不被意外拉低的关键动作。

资源利用率:分子与分母的口径

HPA 的 averageUtilization 计算方式是:利用率 = 当前指标值 ÷ requests × 100%。分母是 requests,不是 limits,也不是节点容量。这一点极易被误解:如果某 Deployment 的 CPU requests 设为 200m,实际使用 150m,则利用率为 75%,而不是相对 limit 的 15%。

由此可推出两个工程结论:其一,requests 设得越小,同样的实际用量算出的利用率越高,HPA 越容易触发扩容;其二,若 requests 严重低于真实需求,HPA 会在负载并不高时频繁扩容,造成资源浪费。因此调优 HPA 的第一步往往是校准 requests,而不是调整阈值。

示例:某服务 3 个副本,每个 requests.cpu=200m,当前总用量 420m。则平均利用率 = (420/3) ÷ 200 = 70%。若目标阈值设为 60%,HPA 期望副本数 = ceil(3 × 70/60) = ceil(3.5) = 4,即扩容到 4 个副本。

Metrics API 与自定义指标

HPA 读取指标依赖 Metrics API 体系,分为三条链路:

  • resource metrics(metrics.k8s.io):由 metrics-server 提供 CPU、内存的实时用量,支撑 type: Resource 的 HPA,是最常用的基础链路。
  • custom metrics(custom.metrics.k8s.io):由 Prometheus Adapter 等适配器暴露,指标与某个 Kubernetes 对象关联,如“每个 Pod 的 QPS”,支撑 type: Pods 或 type: Object。
  • external metrics(external.metrics.k8s.io):来自集群外部系统,如消息队列积压数、云监控指标,支撑 type: External。

自定义指标的价值在于:CPU 利用率并不总能代表真实压力。例如消费型服务在 CPU 不高时,Kafka 消费延迟可能已经飙升,此时用“待消费消息数”作为扩缩容信号更准确。配置时需在 HPA 中通过 metrics 字段声明指标名、目标类型与目标值,并确保适配器已注册对应的 APIService。

资源模型 → 度量 → 扩缩容决策链路 Pod 资源声明 requests 调度依据 · 利用率分母 limits 运行边界 · 限流/OOM QoS 等级 Guaranteed / Burstable / BestEffort Metrics API 体系 metrics.k8s.io metrics-server · CPU/内存 custom.metrics.k8s.io Prometheus Adapter · QPS external.metrics.k8s.io 队列积压 · 云监控 HPA 决策 利用率 = 用量 / requests × 100% 期望副本 = ceil(当前 × 利用率/阈值) 输出:scale 目标副本数 计算示例:requests 如何影响扩容结果 场景 A:requests = 200m 用量 150m → 利用率 75% 场景 B:requests = 500m 用量 150m → 利用率 30% 阈值 60% 时 A 扩容 / B 不扩容 结论:requests 是利用率的分母,校准 requests 比调阈值更根本 requests 偏小 → 频繁扩容;requests 偏大 → 扩容迟钝、资源浪费

工程实践中的校准方法

把上述模型落到操作上,可按以下顺序推进。首先用 kubectl top pod 观察一段时间内的真实用量分布,取 P95 而非平均值作为 requests 参考,因为扩缩容要覆盖峰值而非均值。其次检查 QoS 等级,用 kubectl get pod -o jsonpath='{.status.qosClass}' 确认关键服务是否为 Guaranteed 或预期等级。然后核对 HPA 的分母口径,确保 averageUtilization 对应的 requests 与监控面板中的分母一致,避免“面板显示 40%、HPA 却按 80% 扩容”的口径错位。最后,当 CPU 指标与业务压力脱节时,引入自定义指标,把扩缩容信号切换到更贴近真实负载的维度。

常见误区:把 limits 当作利用率分母,或为追求高装箱率把 requests 压到远低于实际用量。前者会让 HPA 长期不触发,后者会让 HPA 在低负载下反复扩容,两者都会破坏自动扩缩容的稳定性。

资源模型与度量口径是自动扩缩容的地基。requests 决定调度与利用率分母,limits 决定运行边界,QoS 决定驱逐优先级,Metrics API 决定信号来源。只有这四者口径一致,后续的 HPA 阈值、VPA 推荐值和节点扩容判断才具备可比性。