K8s HPA的原理

HPA 的本质就是:一个定时循环的控制器,根据"当前负载 / 目标值"的比例,用一个简单的公式不停地重算副本数,然后去改 Deployment 的 spec.replicas


一. HPA 解决什么问题?

在 K8s 里,你给 Deployment 写死 replicas: 3,遇到流量高峰就会被打爆,流量低的时候又浪费资源。

HorizontalPodAutoscaler(HPA)做的事就是:

  • 监控某个工作负载(Deployment / StatefulSet 等)的一些指标;

  • 周期性地根据这些指标计算"应该有多少个 Pod";

  • 自动修改目标对象的副本数,让副本数在 [minReplicas, maxReplicas] 范围内跟着负载走。Kubernetes+1


二. HPA 的几个关键组件

  1. HPA 对象(YAML 里的那个 kind: HorizontalPodAutoscaler

    里面主要几项:

    • scaleTargetRef:要控制的对象,比如某个 Deployment。

    • minReplicas / maxReplicas:最小、最大 Pod 数。

    • metrics:用什么指标来驱动扩缩容(CPU、内存、QPS、自定义指标、外部指标等)。Red Hat Docs+1

    • (可选)behavior:控制扩/缩容的速度、稳定窗口等。stormforge.io

  2. HPA 控制器(kube-controller-manager 里的一个控制循环)

    • 运行在控制面中;

    • 每隔一段时间(默认 15 秒) 去拉一次目标对象的指标,然后计算期望副本数;Kubernetes

    • 把算出来的值写回到目标的 spec.replicas

  3. Metrics 管道

    HPA 并不直接采集 CPU,它是通过 K8s 指标 API 拿数据的:Medium+1

    • metrics.k8s.io(Resource Metrics API):默认的 CPU / 内存指标(一般由 Metrics Server 提供),最常用。

    • custom.metrics.k8s.io(Custom Metrics API):跟 K8s 对象绑定的自定义指标,比如"每个 Pod 的 QPS"。

    • external.metrics.k8s.io(External Metrics API):外部系统指标,比如"消息队列长度"。

    HPA 只负责"拉 API + 算副本数",至于这些 API 后面连的是 Prometheus、CloudWatch 还是别的东西,是通过 metrics adapter 去适配的。Medium


三. HPA 支持的指标类型(v2 API)

autoscaling/v2 里,spec.metrics[*].type 大致有:Red Hat Docs+1

  • Resource / ContainerResource:CPU、内存这类资源指标;

  • Pods:针对每个 Pod 的自定义指标(比如每个 Pod 的 HTTP QPS),然后求平均;

  • Object:针对某个对象整体的指标(例如某个 Service 的总 QPS);

  • External:完全外部的指标(例如外部队列长度)。

每个 metric 里还要设 目标值 target

  • type: Utilization:目标利用率(百分比,例如 CPU 70%);

  • type: AverageValue:每个 Pod 的目标平均值(比如 "每个 Pod 100 QPS");

  • type: Value:对象级别的绝对值(比如 "总共 QPS=1000")。


四. 核心算法:怎么算"需要多少个 Pod"?

无论你监控的是 CPU / 自定义指标,本质上 HPA 都是用一个很简单的比例公式:stormforge.io+3Stack Overflow+3perfectscale.io+3

desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue)

解释一下参数含义(以 CPU 利用率为例):

  • currentReplicas:当前正在运行的 Pod 数;

  • currentMetricValue:当前平均指标值(比如当前平均 CPU 利用率 90%);

  • desiredMetricValue:你配置的目标值(比如目标 CPU 60%)。

举个简单例子(CPU)

目标 CPU 利用率:60%

当前平均 CPU 利用率:90%

当前副本数:4

比例:currentMetricValue / desiredMetricValue = 90 / 60 = 1.5

于是:

desiredReplicas = ceil(4 × 1.5) = ceil(6) = 6

所以 HPA 会把 Deployment 的 replicas 从 4 改到 6,来摊薄负载。

同理,如果当前平均 CPU 是 30%,目标还是 60%,那比值是 0.5:

desiredReplicas = ceil(4 × 0.5) = ceil(2) = 2

就会触发缩容,把 Pod 从 4 个缩到 2 个。

多指标时怎么处理?

v2 可以配置多个 metrics,比如同时看 CPU 和 QPS。

算法是:对每个指标分别算一个 desiredReplicas,然后取其中最大的那个作为最终结果(偏向"宁可多扩不缩"以保证 QoS)。 people.wikimedia.org+2stormforge.io+2

1. desiredMetricValue 到底是什么?

CPU 利用率(type: Utilization 这个场景下:

  • desiredMetricValue = 你在 HPA 里配置的"目标利用率百分比"

  • 比如你写:

    复制代码
    metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

    那么:

    • desiredMetricValue = 60(%)

    • 含义是:希望"所有 Pod 的平均 CPU 利用率 ≈ 60%(相对于它们自己的 request)"

换句话说:你是希望"使用量 ≈ request 的 60%"。


2. 这里的"利用率"跟 request 的关系

CPU Utilization 的定义是:

利用率 = 当前 CPU 使用量 / Pod 的 CPU request × 100%

  • 如果一个 Pod 的 resources.requests.cpu = 500m,当前实际用量是 250m

    • 那它的 CPU 利用率就是 250m / 500m = 50%
  • HPA 会对所有 Pod 做平均,得到一个 平均利用率 ,这就是前面说的 currentMetricValue

所以:

  • Pod 的 request 是分母("容量")

  • 当前使用量(usage)是分子

  • desiredMetricValue 是你希望这个"利用率(usage/request)"稳定在多少百分比上,比如 60%。


3. 再用一个具体例子串起来

假设:

  • 每个 Pod 的 requests.cpu = 500m

  • 当前有 4 个 Pod

  • 实际监控到的平均使用量是 450m/Pod

则:

  • 每个 Pod 利用率 = 450m / 500m = 90%

  • 平均利用率 = 90%(currentMetricValue)

  • 你在 HPA 里配置目标是 averageUtilization: 60
    desiredMetricValue = 60%

代入公式:

desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue) = ceil(4 × 90 / 60) = ceil(4 × 1.5) = 6

HPA 就会把副本数从 4 调到 6,让每个 Pod 平均负载降下来,目标是在一段时间后趋近 60% 左右。


4. 小结一句话

  • desiredMetricValue(在 CPU Utilization 场景)不是 request 本身,而是"相对于 request 的目标利用率百分比"。

  • Pod 的 request 用来当分母算"利用率",HPA 配置的是"希望这个比例大概是多少"。


五. 如何避免来回抖动?(抖动抑制 & 缩容稳定窗口)

如果没有"缓冲",指标一抖动就改一次副本数,集群会疯狂扩缩容。K8s 做了几件事来平滑:

  1. 容忍度(tolerance)

    有一个默认 10% 的容忍区间:只有当 currentMetricValue / desiredMetricValue 超过 1.1 或小于 0.9 时才会真正扩缩容。Kubegrade

    • 比如目标 CPU 60%,当前在 63%(63/60 = 1.05),不会扩容;

    • 只有达到 ~> 66% 或 < 54% 左右才会动。

  2. 缩容稳定窗口(scaleDown stabilizationWindowSeconds)

    • 对"缩容"特别敏感,因为缩容错了会直接影响可用性;

    • 通常会配置一个窗口(比如 300 秒),HPA 会在这个窗口里对多次计算结果做一个"保守"的合并(一般取这段时间内最大的 desiredReplicas ,防止刚缩下去马上又扩回来)。stormforge.io

  3. 扩缩容速率限制(policies)

    spec.behavior.scaleUp/scaleDown.policies 里,你可以限制每个周期最多扩/缩多少个 Pod 或多少百分比,例如:stormforge.io

    • "每 15 秒最多扩容 100%";

    • "每 60 秒最多缩容 10%"。


六. HPA 和其他自动扩缩工具的边界

很多人会把几个概念混在一起,这里顺便帮你厘清下:CloudRaft+1

  • HPA(HorizontalPodAutoscaler)

    • 调的是 Pod 的数量

    • 前提是集群里已经有足够 Node 能跑这些 Pod。

  • VPA(VerticalPodAutoscaler)

    • 调的是 Pod 里 单个容器的资源 request/limit(比如 CPU request 从 200m 调到 500m);

    • 适合长期稳定 workload 的"容量调优"。

  • Cluster Autoscaler

    • 调的是 Node 的数量

    • 当 HPA 想扩 Pod 但 Node 不够时,CA 会去加机器。

三者一起配合,才是完整的自动扩缩容体系。

相关推荐
会飞的小蛮猪1 小时前
RKE2 部署K8S v1.34.2+rke2r1(Ubuntu2204)离线安装
云原生·容器·kubernetes
qq_213059431 小时前
CKA认证笔记(1.28版本)
笔记·docker·kubernetes
wxl7812271 小时前
零踩坑部署DeepSeek-OCR API:基于Docker+CUDA 11.8的完整指南
docker·容器·deepseek-ocr
小坏讲微服务1 小时前
K8S 部署 Spring Cloud Alibaba 微服务企业实战完整使用
spring cloud·docker·微服务·云原生·容器·kubernetes·k8s
隐语SecretFlow1 小时前
如何基于Docker集群组网模式来部署Kuscia?
运维·docker·容器
了一梨1 小时前
Docker基础使用
linux·docker·容器
mobº1 小时前
K8s 集群部署微服务 - DevOps(一)
微服务·kubernetes·devops
阿里云云原生1 小时前
Nginx Ingress 退役:阿里云云原生 API 网关的迁移方案与实操详解
nginx·阿里云·云原生
阿里云云原生1 小时前
阿里云 ARMS 自定义指标采集:打破传统 APM 局限,实现业务可视化监控
数据库·阿里云·云原生·oracle·arms