何时应在 Kubernetes 中使用水平 Pod 自动缩放 (HPA) ?

简短回答:当你的工作负载可以运行多个相同副本且需求会波动时,使用 HPA——按 CPU/内存、应用指标(RPS/延迟)或外部队列/积压指标进行扩缩容。 不要将 HPA 用于单副本有状态服务,或者当真正的瓶颈是节点容量或下游限制时(DB 连接、第三方速率限制)。

Tl;DR

  • 对于可进行水平拆分的工作负载,当每个 Pod 的指标或外部指标能够反映负载时,请使用 HPA。
  • 使用资源/自定义/外部指标(CPU、RPS、队列深度);并结合 Cluster Autoscaler 实现节点容量扩缩。
  • 使用 KEDA 实现事件驱动的缩容到零或外部扩缩;使用处于建议模式的 VPA 来确定资源请求值。

快速决策清单 (是/否)

  • 工作负荷在多个副本之间是无状态的还是可分区的? (是→ HPA 候选人)
  • 是否可以将负载作为每个 Pod 的指标或外部指标来监测(CPU、每秒请求数、队列深度)? (是→HPA适用)
  • 群集可以计划更多 Pod(群集自动缩放程序或备用容量)吗? (是→继续;如果否,则启用节点自动缩放)
  • 下游服务(数据库池、第三方 API)是否限制并发? (是→添加限流/连接池,或优先采用纵向扩展)

决策矩阵(工作负荷→最佳指标→推荐缩放器)

工作负荷类型 最佳目标指标 推荐的缩放器
Web/API (无状态) 每个 Pod 的 CPU 或 RPS HPA (+VPA 建议 + 群集自动缩放程序)
后台队列工作器 队列长度或消息数/秒 HPA 通过外部指标或 KEDA (KEDA 支持从小到零)
单实例数据库或有状态应用 N/A (不可水平分区) VPA 或手动缩放
Batch/临时事件辅助角色 事件积压 具有外部指标的 KEDA 或 HPA

HPA 的工作原理(简单的控制循环和重要字段)

  • 组件:HPA 控制器(控制平面)+ 指标提供程序(通过适配器或 KEDA 提供资源指标、自定义/外部指标 API 的指标服务器)。
  • 控制循环(高级别):HPA 控制器轮询指标 API → 根据每个已配置的指标计算 desiredReplicas → 取计算得到的最大 desiredReplicas → 应用 min/max 和行为规则(策略/稳定化)→ 更新目标资源上的 spec.replicas → 重复。 有关详细信息,请参阅 Kubernetes HPA 文档
  • 公式(计算所需副本的方式):desiredReplicas = ceil(current_total/ target_per_pod)。 控制器为每个配置的指标计算 desiredReplicas,然后在应用 min/max 和行为之前使用最大值(此指标优先行为记录在 HPA 文档中)。
  • 重要的自动缩放/v2 字段:minReplicas、maxReplicas、指标(Resource、Pods、Object、External)、行为(scaleUp/scaleDown 策略和稳定WindowSeconds)。
  • 使用 behavior 配置来限制变更速率并避免抖动;stabilizationWindowSeconds 是 scaleDown 平滑处理的关键调节参数。

示例行为片段 (自动缩放/v2)

behavior:
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
      - type: Percent
        value: 100
        periodSeconds: 60
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
      - type: Pods
        value: 1
        periodSeconds: 60

何时使用 HPA (按指标类型/常见用例)

  1. CPU/内存(资源指标)
    • 当每个 Pod 的 CPU 或内存利用率与容量需求相关,且 Pod 设置了正确的资源请求时,请使用 HPA。 Web API 和无状态微服务的典型情况。
    • 实际起点:在 60-80% 范围内以平均 CPU 利用率为目标,并通过负载测试进行优化。 HPA 从 Pod 请求计算利用率,因此必须设置请求。
  2. 自定义群集内指标 (Prometheus / 自定义指标)
    • 当应用级信号(请求数/秒、延迟、队列使用者/pod)比 CPU 更好地表示负载时,请使用 HPA。
    • 使用 Prometheus + prometheus-adapter(custom.metrics.k8s.cn)或其他自定义指标提供程序暴露指标,并在 HPA 中将这些指标设为目标指标。
  3. 外部指标(队列、云端积压)
    • 当扩缩容需要根据队列长度(RabbitMQ、Azure 服务总线)、Event Hubs 或云监控指标等外部信号做出响应时,请使用 HPA(通过外部指标 API)或 KEDA。
    • 如果需要缩放到零或严格的事件驱动行为,首选 KEDA — 它原生集成外部缩放程序并支持从零缩放(KEDA 文档)。

何时不应使用 HPA

  • 单副本有状态服务(数据库、Pod 内唯一状态):除非能够安全地进行分片/分区,否则不适合使用 HPA。
  • 当瓶颈出现在节点级别(GPU、磁盘 I/O、节点 CPU)而不是 Pod 级别时:应优先选择节点池自动扩缩容或垂直扩缩容。
  • 当下游系统(DB 连接池、缓存、第三方 API)具有严格的并发限制时:缩放 Pod 且不会增加下游容量可能会恶化故障,请参阅下面的“下游和操作注意事项”。
  • 如果需要缩容到零,仅靠 HPA 无法做到这一点;请使用 KEDA 或外部控制器。

多个指标、优先级和示例

  • 如果配置多个指标,HPA 控制器会独立计算每个指标的 desiredReplicas 值,然后选择最大的 desiredReplicas 作为缩放的基础。 之后,将应用 minReplicas/maxReplicas 和行为策略(源: Kubernetes HPA 文档)。
  • 示例:CPU 目标计算 5 个副本,请求/秒的目标计算 12 个副本→ HPA 将选取 12 个副本(然后最小/最大值和行为策略可以修改最终应用的更改)。
  • 为避免突然超调,请结合使用基于百分比的扩容策略,以及合理的 scaleDown stabilizationWindowSeconds 设置(请参阅上面的 behavior 配置片段)。

HPA 与 VPA 与群集自动缩放程序与 KEDA (简短指南)

  • HPA:根据指标对副本进行水平扩缩容。 最适合可分区的工作负载。
  • VPA:调整 Pod 的资源请求/限制(垂直)。 最适合非并行工作负荷或设置合理的默认值。
  • 集群自动扩缩器(或 Karpenter):扩缩节点规模以满足调度请求(节点级容量)。 当 Pod 由于没有可用节点而处于 Pending 状态时使用。
  • KEDA:事件驱动的自动缩放程序,它集成了外部触发器,并支持事件工作负荷的缩放到零。

常见模式:使用处于推荐模式的 VPA 来设置基线请求,使用 HPA 扩缩副本,并使用集群自动扩缩器(或 Karpenter)提供节点容量。 当您需要缩减到零,或直接与外部事件源集成时,请使用 KEDA。

注意:托管 Kubernetes 服务(AKS/GKE/EKS)可能会预装指标提供程序,或提供集成的自动扩缩容功能。 AKS 群集自动缩放器文档


下游和操作注意事项(常见问题)

  • 数据库连接池:增加副本数会增加并发连接数。 可通过连接池(例如 PgBouncer)、限制每个 Pod 的并发数,或在扩缩 Pod 之前增大数据库连接池大小来缓解。
  • API 速率限制与第三方配额:确保下游系统能够处理 Pod 扩容后产生的请求量;考虑采用客户端限流。
  • PodDisruptionBudgets (PDB):PDB 不会阻止 HPA 纵向扩展,但可能会影响维护操作和排水行为:确保缩放策略与 PDB 保持一致。
  • 启动和预热的影响:initContainers、缓存预热或较长的冷启动时间都可能使指标失真并引发波动——应使用就绪探针/启动探针和稳定窗口。
  • 推荐的运行方法:设置保守的扩缩容速率,调整资源请求/限制和探针配置,在非生产环境中进行测试,并在下游系统成为瓶颈时增加基于 SLO 的限流。

配置清单与安全上线步骤

确保指标和基于角色的访问控制(RBAC):

  • 部署 metrics-server 以获取资源指标(或使用托管服务提供商)。
  • 如果需要,可为自定义指标(custom.metrics.k8s.io)部署 Prometheus 和 prometheus-adapter。
  • 对于外部或事件扩缩器,可以考虑使用 KEDA。

使用以下内容编写 HPA(autoscaling/v2):

  • minReplicas 和 maxReplicas,
  • 显式指标和行为(scaleUp/scaleDown 策略),
  • Pod 上的就绪情况和启动探测,
  • 合理的资源请求,使资源指标有意义。

安全测试清单(如何安全地测试 HPA):

  1. 在启用了类似节点大小和自动缩放的非生产命名空间/群集中进行测试。
  2. 先采用保守的最小/最大副本数配置和较温和的扩容策略(例如,每分钟最多增长 100%)。
  3. 进行渐进式负载测试,监控 desiredReplicas、currentReplicas 以及处于 Pending 状态的 Pod。
  4. 在提高激进程度之前,先反复调整资源请求/限制、就绪探针和行为策略。

AKS 和节点自动缩放说明:

  • AKS 和其他云服务可能会预装 metrics-server,或者提供托管式自动扩缩器集成。 启用群集自动缩放程序的示例 AKS CLI: az aks nodepool update --resource-group myRG --cluster-name myAKS --name node-pool1 --enable-cluster-autoscaler --min-count 1 --max-count 5

卡彭特注意:Karpenter 是一种侧重于快速预配的替代节点自动缩放方法;如果需要快速节点预配,请考虑它。


可用的 YAML 示例

基于 CPU 的 HPA (自动缩放/v2):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: webapi-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: webapi
  minReplicas: 3
  maxReplicas: 12
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60

HPA 使用 Prometheus 公开的自定义指标(通过 prometheus-adapter):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-requests-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "100"

有关映射查询,请参阅prometheus-adapter 文档

KEDA ScaledObject (Azure 服务总线) - 支持从小到零:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: sb-queue-scaledobject
  namespace: workers
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: event-worker
  minReplicaCount: 0
  maxReplicaCount: 20
  pollingInterval: 30
  cooldownPeriod: 300
  triggers:
    - type: azure-servicebus
      metadata:
        queueName: orders-queue
        queueLength: "50"
      authenticationRef:
        name: keda-azure-credentials

KEDA 文档


可观测性、警报和 SRE 示例

建议的告警(可直接复制的 Prometheus 示例——请根据你的导出配置调整指标名称):

  1. 当 HPA 的期望值 > 当前值并持续 > 5 分钟时发出告警(调度容量问题)

    alert: HPAUnschedulable
    expr: (kube_hpa_status_desired_replicas - kube_hpa_status_current_replicas) > 0
    for: 5m
    labels:
      severity: page
    annotations:
      summary: "HPA desired replicas exceed current replicas for >5m (possible scheduling issue)"
    
  2. 对命名空间中处于挂起状态的 Pod 发出告警

    alert: PodsPendingHigh
    expr: sum(kube_pod_status_phase{phase="Pending", namespace="production"}) > 3
    for: 2m
    labels:
      severity: ticket
    annotations:
      summary: "High number of Pending pods in production"
    
  3. 频繁缩放的警报(点击)

    alert: HPAFlapping
    expr: increase(kube_hpa_status_replicas_last_transition_count[10m]) > 5
    for: 0m
    labels:
      severity: warning
    annotations:
      summary: "Frequent HPA scaling events detected"
    

仪表板显示:

  • HPA:currentReplicas、desiredReplicas、lastScaleTime、HPA 所使用的指标值
  • Pod 运行状况:挂起的 Pod、FailedScheduling 事件、Pod 重启次数
  • 下游:数据库连接使用情况、错误率、外部 API 错误/429 速率

操作和调试命令(快速参考)

  • HPA 列表:kubectl get hpa -n
  • 描述 HPA(查找当前/当前指标、desiredReplicas、lastScaleTime、事件): kubectl describe hpa -n
  • 用于在描述输出中检查的字段:currentReplicas、desiredReplicas、指标(当前/目标值)、lastScaleTime、事件(指标提供程序的错误或缩放失败)
  • 查看资源使用情况(需要 metrics-server): kubectl top pods -n
  • 检查 Pending Pod 和调度失败:kubectl get pods -n | grep Pendingkubectl describe pod -n(在 kubectl describe pod -n 中查找 FailedScheduling)
  • 检查指标提供程序日志: kubectl logs -n kube-system deploy/metrics-serverkubectl logs -n deploy/prometheus-adapter
  • 应用 HPA 清单: kubectl apply -f hpa.yaml

快速故障排除提示:

  • HPA 显示 desiredReplicas > currentReplicas,且 Pod 仍处于 Pending 状态 → 很可能是节点容量不足;启用集群自动扩缩器或增加节点池。
  • HPA 显示事件中的指标错误,→检查适配器 RBAC/config 和指标提供程序日志。
  • HPA 缩放速度太快/速度过慢→优化行为策略(百分比/Pod 限制)和稳定窗口。

  • CPU 目标:从平均利用率约 60% 开始(常见范围为 60–80%),并根据每个工作负载进行调整。
  • minReplicas:为了保证可用性,至少应设为 1;如果需要将 minReplicas 设为 0,请使用 KEDA。
  • maxReplicas:根据容量规划和成本进行设置;确保 Cluster Autoscaler 的限制允许将节点增加到所需容量。
  • stabilizationWindowSeconds:scaleDown ≈ 300s(5 分钟)通常可作为一个常见的起始值,以避免快速缩容;请根据工作负载进行调整。
  • 缩放策略:限制每个周期的增长百分比上限(例如,允许每分钟最多增长 100%),以避免使下游系统不堪重负。
  • 就绪/启动探针:务必配置,以确保 Pod 在完全就绪之前不会接收流量。

注意:特定的控制器计时默认值和确切行为可能因 Kubernetes 版本和分发而异 - 检查群集版本的 HPA 文档


启用 HPA 前的常见陷阱和检查清单

  • Pod 资源请求缺失或不正确,→基于资源的 HPA 目标将产生误导。
  • 没有指标提供程序(metrics-server/prometheus-adapter/KEDA)→ HPA 无法读取指标。
  • 集群没有可用节点容量,且未启用集群自动扩缩器 → 这些 Pod 将一直处于 Pending 状态。
  • 混合使用 HPA 和 VPA:避免让两个控制器同时主动调整资源请求——让 VPA 以建议模式运行,并由 HPA 负责扩缩副本数。
  • 启动时出现尖峰(initContainers、冷缓存)且未配置探针时→调整稳定时间窗口,或手动预热实例。
  • RBAC 配置错误:确保指标适配器和 HPA 控制器具有读取指标所需的权限。

快速常见问题解答

问:HPA 有什么好处? 答:使用正确的指标和节点自动缩放时,自动调整副本计数以更改负载、提高利用率和成本,并维护延迟目标。

问:HPA 如何计算期望副本数? 答:它会读取已配置的指标,针对每个指标计算 desiredReplicas = ceil(current_total / target_per_pod),取计算结果中的最大值,然后再应用 min/max 和行为策略(来源:HPA 文档)。

问:HPA 能否缩放到零? 答:否 - 普通 HPA 无法缩放为零。 使用 KEDA 实现缩容到零(KEDA 文档)。

问:如何根据队列长度或 RPS 进行缩放? 答:将队列长度/RPS 公开为外部或自定义指标(Prometheus 适配器或外部指标 API),或使用 KEDA 进行事件驱动的缩放。


References