3. Horizontal Pod Autoscaler基础

Horizontal Pod Autoscaler(HPA)是 OpenShift 中最常用的工作负载水平伸缩控制器。它不直接创建 Pod,而是通过调整 Deployment、ReplicaSet、StatefulSet 等可伸缩对象的 replicas 字段,间接改变实际运行的 Pod 数量。理解 HPA,关键要抓住四件事:控制回路如何运转、指标从哪里来、期望副本数怎么算、以及为什么需要冷却窗口。

一、HPA 的控制回路

HPA 本质上是一个周期性运行的负反馈控制回路。它每隔一段时间(OpenShift 默认约 15 秒,由 --horizontal-pod-autoscaler-sync-period 控制)执行一次同步:从指标源采集当前指标,与用户设定的目标值比较,计算出一个期望副本数,再通过 Scale 子资源把副本数写入目标工作负载。整个过程可以概括为“采集 → 比较 → 计算 → 写入 → 等待下一轮”。

需要特别注意的是,HPA 只负责“决定要几个副本”,真正把 Pod 调度、拉镜像、启动起来的是 Deployment/ReplicaSet 控制器和调度器。因此从 HPA 调整副本数到新 Pod 真正 Ready 并开始分担流量,存在明显延迟。这个延迟正是冷却窗口和稳定窗口存在的原因。

HPA 控制回路与指标来源 指标来源 metrics-server (CPU / 内存) 自定义 / 外部指标适配器 HPA 控制器 每 15s 同步一次 期望副本 = 当前副本 × (当前指标 / 目标指标) 目标工作负载 Deployment / RS replicas 字段 Scale 子资源 实际 Pod 指标反馈 冷却窗口 扩容稳定窗口(默认 0s,可立即扩容) | 缩容稳定窗口(默认 300s,避免抖动)

二、指标来源:HPA 看什么

HPA 支持三类指标,它们决定了 HPA 能“感知”什么:

  • 资源指标:CPU 和内存利用率,来自 metrics-server。这是最常见、最容易上手的来源。利用率是相对于 Pod 中容器 resources.requests 的百分比,而不是相对于节点容量或 limit。
  • 自定义指标:来自应用自身暴露的指标,例如每秒请求数、队列长度,通过 Prometheus Adapter 等适配器接入。
  • 外部指标:来自集群外部系统,例如云消息队列积压量、云监控指标。

这里有一个极易踩坑的点:资源指标的分母是 requests,不是 limit。如果某个容器没有设置 CPU requests,HPA 就无法计算该 Pod 的 CPU 利用率,会直接报错或跳过。因此在启用 HPA 前,必须为容器设置合理的 requests。例如一个容器设置 requests.cpu: 200m,当它实际使用 100m 时,利用率就是 50%。

三、目标值计算:期望副本数怎么来

HPA 的核心公式是:

期望副本数 = ceil( 当前副本数 × ( 当前指标值 / 目标指标值 ) )

以 CPU 利用率为例,假设当前有 4 个副本,目标 CPU 利用率设为 60%,而当前平均利用率是 90%,则:

期望副本数 = ceil( 4 × ( 90% / 60% ) ) = ceil(6) = 6

HPA 会把副本数从 4 调到 6。反过来,如果当前平均利用率降到 30%,则 ceil(4 × 0.5) = 2,HPA 会尝试缩到 2 个副本。计算完成后,结果还会被 minReplicas 和 maxReplicas 夹紧,防止越界。

需要理解的是,HPA 使用的是“当前副本数”而不是“上一轮期望值”,并且每轮都重新采集指标。这意味着指标波动会直接反映到副本数上,这也是为什么需要稳定窗口来平滑抖动。

四、冷却窗口与稳定窗口

如果 HPA 每 15 秒就根据瞬时指标调整一次副本数,系统会剧烈震荡:扩容后指标下降,立刻缩容,缩容后指标又上升,再扩容。为避免这种抖动,HPA 引入了两个时间维度的保护:

窗口类型默认值作用
扩容稳定窗口0 秒允许快速扩容,及时应对突发流量
缩容稳定窗口300 秒缩容前观察一段时间,取窗口内最大推荐值,避免误缩
同步周期约 15 秒HPA 重新采集指标并计算的间隔

缩容稳定窗口的逻辑是:HPA 会记录过去 300 秒内所有计算出的期望副本数,缩容时取其中的最大值作为最终结果。也就是说,即使当前指标显示可以缩到 2 个副本,只要过去 5 分钟内曾推荐过 5 个副本,HPA 仍会保持 5 个,直到这个高推荐值滑出窗口。扩容方向则不受此限制,可以立即执行。

扩容快、缩容慢是 HPA 的默认设计哲学:宁可多留一会儿资源,也不要因为瞬时低谷而缩容,导致下一波流量到来时来不及扩容。

五、一个可参考的 HPA 配置示例

下面是一个基于 CPU 利用率的 HPA 示例,目标利用率 60%,副本范围 2 到 10:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
    scaleUp:
      stabilizationWindowSeconds: 0

要让这个 HPA 正常工作,Deployment 中的容器必须设置 CPU requests,例如 requests.cpu: 200m。部署后可以用 oc get hpa web-hpa 观察 TARGETS 列,它会显示类似 45%/60% 的当前值与目标值对比;oc describe hpa web-hpa 则能看到最近的事件、计算过程和是否触发了稳定窗口。

如果 TARGETS 显示 <unknown>/60%,通常说明 metrics-server 未就绪,或容器缺少 CPU requests。此时 HPA 不会调整副本数,需要先排查指标链路。