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 会去加机器。

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

相关推荐
学Linux的语莫1 天前
kompose、docker转k8s
docker·容器·kubernetes
阿里云云原生1 天前
探秘 AgentRun丨流量一大就瘫痪?如何解决 AI 模型调用之痛
云原生
是Yu欸1 天前
从Ascend C算子开发视角看CANN的“软硬协同”
c语言·开发语言·云原生·昇腾·ascend·cann·开放社区
光头熊1 天前
一次 nerdctl prune -a 导致 Kubernetes 节点不可用的复盘
kubernetes
码界奇点1 天前
基于微服务架构的企业身份与访问管理系统设计与实现
微服务·云原生·架构·车载系统·毕业设计·源代码管理
一点晖光1 天前
docker配置npm环境变量出现问题
docker·容器·npm
一分半心动1 天前
windows docker desktop 安装VibeVoice
运维·docker·容器
LucidX1 天前
Docker核心操作实战
运维·docker·容器
隔壁阿布都1 天前
Docker Compose中的网络管理
运维·docker·容器
yuxb731 天前
kubernetes弹性伸缩
笔记·kubernetes