从零开始的云原生之旅(十):HPA 完全指南:从原理到实践

从零开始的云原生之旅(十):HPA 完全指南:从原理到实践

配置 HPA 后,看着 Pod 自动扩缩容,太爽了!

📖 文章目录

  • 前言
  • [一、HPA 核心概念深度解析](#一、HPA 核心概念深度解析)
    • [1.1 HPA 的三个核心问题](#1.1 HPA 的三个核心问题)
    • [1.2 HPA 计算公式详解](#1.2 HPA 计算公式详解)
    • [1.3 指标类型详解](#1.3 指标类型详解)
  • [二、HPA 配置文件完全解读](#二、HPA 配置文件完全解读)
    • [2.1 基础配置结构](#2.1 基础配置结构)
    • [2.2 Metrics 配置详解](#2.2 Metrics 配置详解)
    • [2.3 Behavior 行为控制](#2.3 Behavior 行为控制)
    • [2.4 完整配置示例](#2.4 完整配置示例)
  • [三、部署第一个 HPA](#三、部署第一个 HPA)
    • [3.1 创建 HPA 配置](#3.1 创建 HPA 配置)
    • [3.2 应用 HPA](#3.2 应用 HPA)
    • [3.3 验证 HPA 状态](#3.3 验证 HPA 状态)
    • [3.4 我踩的坑:TARGETS 显示 unknown](#3.4 我踩的坑:TARGETS 显示 unknown)
  • 四、观察自动扩容
    • [4.1 准备监控窗口](#4.1 准备监控窗口)
    • [4.2 触发扩容](#4.2 触发扩容)
    • [4.3 扩容过程解析](#4.3 扩容过程解析)
    • [4.4 扩容时间线](#4.4 扩容时间线)
  • 五、观察自动缩容
    • [5.1 停止负载](#5.1 停止负载)
    • [5.2 缩容过程解析](#5.2 缩容过程解析)
    • [5.3 为什么缩容这么慢?](#5.3 为什么缩容这么慢?)
  • [六、HPA 行为策略详解](#六、HPA 行为策略详解)
    • [6.1 ScaleUp 策略](#6.1 ScaleUp 策略)
    • [6.2 ScaleDown 策略](#6.2 ScaleDown 策略)
    • [6.3 稳定窗口的作用](#6.3 稳定窗口的作用)
    • [6.4 策略组合示例](#6.4 策略组合示例)
  • [七、多指标 HPA 配置](#七、多指标 HPA 配置)
    • [7.1 CPU + 内存双指标](#7.1 CPU + 内存双指标)
    • [7.2 多指标计算逻辑](#7.2 多指标计算逻辑)
    • [7.3 指标优先级](#7.3 指标优先级)
  • [八、HPA 调优技巧](#八、HPA 调优技巧)
    • [8.1 如何让 HPA 更敏感?](#8.1 如何让 HPA 更敏感?)
    • [8.2 如何避免频繁抖动?](#8.2 如何避免频繁抖动?)
    • [8.3 如何快速扩容、缓慢缩容?](#8.3 如何快速扩容、缓慢缩容?)
    • [8.4 如何设置合理的阈值?](#8.4 如何设置合理的阈值?)
  • 九、常见问题排查
    • [9.1 HPA 不工作](#9.1 HPA 不工作)
    • [9.2 HPA 显示 unknown](#9.2 HPA 显示 unknown)
    • [9.3 HPA 扩容太慢](#9.3 HPA 扩容太慢)
    • [9.4 HPA 频繁抖动](#9.4 HPA 频繁抖动)
    • [9.5 Pod 被 OOMKilled](#9.5 Pod 被 OOMKilled)
  • 结语

前言

在上一篇文章中,我完成了 HPA 的所有准备工作:

  • ✅ 安装了 Metrics Server
  • ✅ 优化了资源配置
  • ✅ 添加了负载测试接口

现在,终于到了最激动人心的时刻 - 配置 HPA,看着 Pod 自动扩缩容!

这篇文章,我会:

  • ✅ 深入理解 HPA 的工作原理
  • ✅ 手把手配置 HPA
  • ✅ 观察和分析自动扩缩容过程
  • ✅ 掌握 HPA 调优技巧
  • 记录所有踩过的坑

一、HPA 核心概念深度解析

1.1 HPA 的三个核心问题

HPA(HorizontalPodAutoscaler)要回答 3 个问题:

复制代码
1. 什么时候扩容/缩容?
   → 根据指标判断(CPU、内存、自定义指标)

2. 扩容/缩容到多少个副本?
   → 根据公式计算期望副本数

3. 扩容/缩容的速度是多少?
   → 根据 behavior 策略控制

1.2 HPA 计算公式详解

HPA 的核心计算公式:

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

ceil: 向上取整函数

举例 1 - CPU 扩容

复制代码
当前状态:
- 当前副本数: 2
- 当前 CPU 使用率: 140%
- 目标 CPU 使用率: 70%

计算:
期望副本数 = ceil(2 × (140% / 70%))
          = ceil(2 × 2)
          = 4

结果: 扩容到 4 个副本

举例 2 - 内存扩容

复制代码
当前状态:
- 当前副本数: 4
- 当前内存使用率: 90%
- 目标内存使用率: 80%

计算:
期望副本数 = ceil(4 × (90% / 80%))
          = ceil(4 × 1.125)
          = ceil(4.5)
          = 5

结果: 扩容到 5 个副本

举例 3 - 缩容

复制代码
当前状态:
- 当前副本数: 10
- 当前 CPU 使用率: 30%
- 目标 CPU 使用率: 70%

计算:
期望副本数 = ceil(10 × (30% / 70%))
          = ceil(10 × 0.43)
          = ceil(4.3)
          = 5

结果: 缩容到 5 个副本

关键点

  • 使用率 > 目标 → 扩容
  • 使用率 < 目标 → 缩容
  • 使用率 ≈ 目标 → 不变

1.3 指标类型详解

HPA 支持 4 种指标类型:

类型 说明 使用场景 示例
Resource CPU、内存 最常用,90% 的场景 CPU > 70% 扩容
Pods 每个 Pod 的自定义指标 业务指标 QPS > 100 扩容
Object Kubernetes 对象的指标 Service、Ingress Ingress RPS > 1000
External 外部指标 云平台、第三方服务 SQS 队列长度 > 100

本篇重点:Resource 类型(CPU 和内存)


二、HPA 配置文件完全解读

2.1 基础配置结构

yaml 复制代码
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa                    # HPA 名称
spec:
  scaleTargetRef:                  # 要控制的对象
    apiVersion: apps/v1
    kind: Deployment
    name: cloudnative-api          # Deployment 名称
  
  minReplicas: 2                   # 最少副本数
  maxReplicas: 10                  # 最多副本数
  
  metrics:                         # 指标配置
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  
  behavior:                        # 行为策略(可选)
    scaleUp: {}
    scaleDown: {}

2.2 Metrics 配置详解

CPU 指标配置

yaml 复制代码
metrics:
- type: Resource                   # 资源类型
  resource:
    name: cpu                      # CPU 指标
    target:
      type: Utilization            # 利用率类型
      averageUtilization: 70       # 目标 70%

计算方式

复制代码
CPU 利用率 = (实际使用的 CPU / requests.cpu) × 100%

例如:
- requests.cpu: 100m
- 实际使用: 70m
- 利用率: 70%

内存指标配置

yaml 复制代码
metrics:
- type: Resource
  resource:
    name: memory                   # 内存指标
    target:
      type: Utilization
      averageUtilization: 80       # 目标 80%

为什么内存阈值通常比 CPU 高?

  • CPU 可以超用(throttling)
  • 内存超用 → OOMKilled(进程被杀)
  • 所以内存要留更多buffer(80% vs 70%)

绝对值配置(不常用)

yaml 复制代码
metrics:
- type: Resource
  resource:
    name: memory
    target:
      type: AverageValue           # 绝对值类型
      averageValue: "100Mi"        # 每个 Pod 平均 100Mi

2.3 Behavior 行为控制

为什么需要 behavior?

默认的 HPA 行为可能不符合你的需求:

  • 扩容可能太慢(流量突增时)
  • 缩容可能太快(导致抖动)
  • 需要细粒度控制

Behavior 结构

yaml 复制代码
behavior:
  scaleUp:                         # 扩容策略
    stabilizationWindowSeconds: 0  # 稳定窗口(0 = 立即)
    policies:
    - type: Percent                # 百分比策略
      value: 100                   # 每次翻倍
      periodSeconds: 15            # 每 15 秒
    - type: Pods                   # 绝对数量策略
      value: 4                     # 或者增加 4 个
      periodSeconds: 15
    selectPolicy: Max              # 选择最激进的策略
  
  scaleDown:                       # 缩容策略
    stabilizationWindowSeconds: 300  # 5 分钟稳定期
    policies:
    - type: Pods
      value: 1                     # 每次减少 1 个
      periodSeconds: 60            # 每 60 秒
    selectPolicy: Min              # 选择最保守的策略

关键参数解释

参数 作用 典型值
stabilizationWindowSeconds 稳定窗口,防止抖动 扩容: 0-60s, 缩容: 300-600s
type: Percent 按百分比调整 50%(增加一半), 100%(翻倍)
type: Pods 按绝对数量调整 1-5 个
periodSeconds 策略周期 15-60 秒
selectPolicy 策略选择 Max(激进), Min(保守)

2.4 完整配置示例

yaml 复制代码
# k8s/v0.3/api/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: cloudnative-api-hpa
  labels:
    app: cloudnative-api
    version: v0.3
spec:
  # 1. 控制目标
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cloudnative-api
  
  # 2. 副本数范围
  minReplicas: 2                   # 最少保持 2 个(高可用)
  maxReplicas: 10                  # 最多扩展到 10 个
  
  # 3. 扩缩容指标
  metrics:
  # CPU 指标
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70     # CPU 超过 70% 扩容
  
  # 内存指标
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80     # 内存超过 80% 扩容
  
  # 4. 扩缩容行为
  behavior:
    # 扩容策略:快速响应
    scaleUp:
      stabilizationWindowSeconds: 0    # 不等待,立即扩容
      policies:
      - type: Percent
        value: 100                     # 可以翻倍
        periodSeconds: 15              # 每 15 秒评估
      - type: Pods
        value: 2                       # 或者加 2 个
        periodSeconds: 60
      selectPolicy: Max                # 选择扩容更多的策略
    
    # 缩容策略:保守缓慢
    scaleDown:
      stabilizationWindowSeconds: 300  # 5 分钟稳定期
      policies:
      - type: Pods
        value: 1                       # 每次只减 1 个
        periodSeconds: 60              # 每 60 秒评估
      selectPolicy: Min                # 选择保守策略

三、部署第一个 HPA

3.1 创建 HPA 配置

创建文件 k8s/v0.3/api/hpa.yaml(内容见上面的完整示例)。

3.2 应用 HPA

bash 复制代码
# 应用 HPA 配置
kubectl apply -f k8s/v0.3/api/hpa.yaml

# 输出:
# horizontalpodautoscaler.autoscaling/cloudnative-api-hpa created

3.3 验证 HPA 状态

Step 1: 查看 HPA 列表

bash 复制代码
kubectl get hpa

预期输出

复制代码
NAME                   REFERENCE                     TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
cloudnative-api-hpa    Deployment/cloudnative-api    <unknown>/70%, <unknown>/80%   2         10        2          10s

等待 15-30 秒后再查看

bash 复制代码
kubectl get hpa cloudnative-api-hpa

预期输出

复制代码
NAME                   REFERENCE                     TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
cloudnative-api-hpa    Deployment/cloudnative-api    5%/70%, 15%/80%   2         10        2          45s

✅ TARGETS 显示实际值了!

TARGETS 字段解读

复制代码
5%/70%, 15%/80%
│  │    │  │
│  │    │  └─ 目标内存利用率: 80%
│  │    └──── 目标 CPU 利用率: 15%
│  └───────── 当前内存利用率: 70%
└──────────── 当前 CPU 利用率: 5%

Step 2: 查看详细信息

bash 复制代码
kubectl describe hpa cloudnative-api-hpa

输出示例

复制代码
Name:                                                  cloudnative-api-hpa
Namespace:                                             default
Labels:                                                app=cloudnative-api
                                                       version=v0.3
Annotations:                                           <none>
CreationTimestamp:                                     Sun, 02 Nov 2025 16:30:00 +0800
Reference:                                             Deployment/cloudnative-api
Metrics:                                               ( current / target )
  resource cpu on pods  (as a percentage of request):  5% (5m) / 70%
  resource memory on pods  (as a percentage of request):  15% (19456Ki) / 80%
Min replicas:                                          2
Max replicas:                                          10
Deployment pods:                                       2 current / 2 desired
Conditions:
  Type            Status  Reason              Message
  ----            ------  ------              -------
  AbleToScale     True    ReadyForNewScale    recommended size matches current size
  ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
  ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
Events:           <none>

关键字段解释

  • Metrics: 当前值 / 目标值
  • AbleToScale: 是否可以扩缩容
  • ScalingActive: 指标是否有效
  • Events: 扩缩容事件(初始时为空)

3.4 我踩的坑:TARGETS 显示 unknown

问题现象

bash 复制代码
$ kubectl get hpa
NAME                   TARGETS           REPLICAS
cloudnative-api-hpa    <unknown>/70%     2

可能原因

原因 1: Metrics Server 未安装或未就绪

bash 复制代码
# 检查 Metrics Server
kubectl get deployment metrics-server -n kube-system

# 如果不存在或不就绪,重新安装
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 本地环境需要打补丁
kubectl patch deployment metrics-server -n kube-system --type='json' -p='[
  {
    "op": "add",
    "path": "/spec/template/spec/containers/0/args/-",
    "value": "--kubelet-insecure-tls"
  }
]'

原因 2: Pod 未设置 resources.requests

bash 复制代码
# 检查 Pod 配置
kubectl get pod -l app=cloudnative-api -o yaml | grep -A 5 "resources:"

# 确保有 requests 配置:
# resources:
#   requests:
#     cpu: 100m
#     memory: 128Mi

原因 3: 指标还没收集(刚启动)

bash 复制代码
# 等待 30-60 秒让 Metrics Server 收集数据
sleep 30
kubectl get hpa cloudnative-api-hpa

原因 4: Pod 未就绪

bash 复制代码
# 检查 Pod 状态
kubectl get pods -l app=cloudnative-api

# 确保所有 Pod 都是 Running 且 READY 是 1/1

原因5:负载太高了,Pod没办法及时处理健康探针和准备探针,Pod不断重启,无法收集信息


四、观察自动扩容

4.1 准备监控窗口

强烈建议打开 4 个终端窗口同时监控

终端 1 - HPA 实时监控

bash 复制代码
kubectl get hpa cloudnative-api-hpa -w

终端 2 - Pod 实时监控

bash 复制代码
kubectl get pods -l app=cloudnative-api -w

终端 3 - 资源使用监控(PowerShell):

powershell 复制代码
while ($true) {
    Clear-Host
    Write-Host "=== $(Get-Date -Format 'HH:mm:ss') ===" -ForegroundColor Cyan
    kubectl top pods -l app=cloudnative-api
    Start-Sleep -Seconds 5
}

终端 4 - 执行命令

bash 复制代码
# 用于发送负载请求

4.2 触发扩容

方式 1: 循环发送 CPU 负载(PowerShell):

powershell 复制代码
# 获取 Service URL(Minikube)
$serviceUrl = minikube service cloudnative-api-service --url

# 循环发送 50 个请求
for ($i = 1; $i -le 50; $i++) {
    Write-Host "Request $i" -ForegroundColor Yellow
    Invoke-WebRequest -Uri "$serviceUrl/api/v1/workload/cpu?iterations=30000000" -TimeoutSec 30 | Out-Null
    Start-Sleep -Milliseconds 100
}

方式 2: 并发发送请求(Bash):

bash 复制代码
# 并发 10 个请求
for i in {1..10}; do
  (curl -s "$SERVICE_URL/api/v1/workload/cpu?iterations=30000000" &)
done

4.3 扩容过程解析

观察终端 1(HPA)的变化

复制代码
TIME    TARGETS         REPLICAS
16:30   5%/70%, 15%/80%    2        ← 初始状态:低负载
16:31   85%/70%, 25%/80%   2        ← 负载上升:CPU 超过目标
16:31   85%/70%, 25%/80%   4        ← 扩容触发:2 → 4
16:32   65%/70%, 30%/80%   4        ← 新 Pod 分担负载
16:33   45%/70%, 20%/80%   4        ← 趋于稳定

观察终端 2(Pod)的变化

复制代码
NAME                               READY   STATUS              AGE
cloudnative-api-xxxxxxxxx-aaa      1/1     Running             10m    ← 原有
cloudnative-api-xxxxxxxxx-bbb      1/1     Running             10m    ← 原有
cloudnative-api-xxxxxxxxx-ccc      0/1     Pending             1s     ← 新建(等待调度)
cloudnative-api-xxxxxxxxx-ddd      0/1     Pending             1s     ← 新建(等待调度)
cloudnative-api-xxxxxxxxx-ccc      0/1     ContainerCreating   5s     ← 创建容器
cloudnative-api-xxxxxxxxx-ddd      0/1     ContainerCreating   5s
cloudnative-api-xxxxxxxxx-ccc      1/1     Running             15s    ← 就绪
cloudnative-api-xxxxxxxxx-ddd      1/1     Running             15s    ← 就绪

观察终端 3(资源)的变化

复制代码
=== 16:30:00 ===
NAME                               CPU(cores)   MEMORY(bytes)
cloudnative-api-xxxxxxxxx-aaa      15m          85Mi          ← 空闲
cloudnative-api-xxxxxxxxx-bbb      18m          90Mi

=== 16:31:00 ===
NAME                               CPU(cores)   MEMORY(bytes)
cloudnative-api-xxxxxxxxx-aaa      180m         150Mi         ← 高负载!
cloudnative-api-xxxxxxxxx-bbb      175m         145Mi

=== 16:32:00 ===
NAME                               CPU(cores)   MEMORY(bytes)
cloudnative-api-xxxxxxxxx-aaa      95m          120Mi         ← 负载分散
cloudnative-api-xxxxxxxxx-bbb      90m          118Mi
cloudnative-api-xxxxxxxxx-ccc      88m          115Mi         ← 新 Pod
cloudnative-api-xxxxxxxxx-ddd      92m          120Mi         ← 新 Pod

4.4 扩容时间线

完整的扩容时间线:

复制代码
T+0s    负载开始,CPU 从 5% 上升
T+15s   Metrics Server 采集到新指标
T+15s   HPA 检查指标,发现 CPU 85% > 70%
T+16s   HPA 计算:ceil(2 × 85% / 70%) = 3
        但由于 behavior 策略允许翻倍,决定扩到 4
T+16s   HPA 更新 Deployment.replicas = 4
T+17s   Deployment 创建 2 个新 Pod(Pending)
T+20s   调度器分配节点,Pod 状态变为 ContainerCreating
T+25s   容器启动,应用初始化
T+30s   Startup Probe 通过
T+35s   Readiness Probe 通过,Pod 变为 Running (1/1)
T+35s   Service 开始将流量分发到新 Pod
T+40s   负载均衡,CPU 从 85% 降至 65%
T+50s   系统稳定

关键延迟

  • Metrics 采集延迟:15 秒
  • HPA 计算延迟:<1 秒
  • Pod 启动延迟:15-20 秒
  • 总延迟:30-40 秒

五、观察自动缩容

5.1 停止负载

bash 复制代码
# 按 Ctrl+C 停止发送请求

# 或者等待所有请求完成

5.2 缩容过程解析

观察 HPA 的变化

复制代码
TIME    TARGETS         REPLICAS
16:35   45%/70%, 20%/80%   4        ← 负载停止
16:36   15%/70%, 18%/80%   4        ← CPU 降低
16:37   10%/70%, 16%/80%   4        ← 仍然 4 个
16:38   8%/70%, 15%/80%    4        ← 稳定窗口中...
16:39   5%/70%, 15%/80%    4        ← 稳定窗口中...
...     (等待 5 分钟)
16:40   5%/70%, 15%/80%    4        ← 稳定窗口中...
16:41   5%/70%, 15%/80%    3        ← 缩容:4 → 3
16:42   6%/70%, 16%/80%    3        ← 观察中
16:43   5%/70%, 15%/80%    2        ← 缩容:3 → 2
16:44   5%/70%, 15%/80%    2        ← 回到最小值

观察 Pod 的变化

复制代码
=== 16:41:00 ===
cloudnative-api-xxxxxxxxx-aaa      1/1     Running       10m
cloudnative-api-xxxxxxxxx-bbb      1/1     Running       10m
cloudnative-api-xxxxxxxxx-ccc      1/1     Running       5m
cloudnative-api-xxxxxxxxx-ddd      1/1     Terminating   5m    ← 被终止

=== 16:43:00 ===
cloudnative-api-xxxxxxxxx-aaa      1/1     Running       10m
cloudnative-api-xxxxxxxxx-bbb      1/1     Running       10m
cloudnative-api-xxxxxxxxx-ccc      1/1     Terminating   5m    ← 又一个被终止

=== 16:44:00 ===
cloudnative-api-xxxxxxxxx-aaa      1/1     Running       10m   ← 保留
cloudnative-api-xxxxxxxxx-bbb      1/1     Running       10m   ← 保留

5.3 为什么缩容这么慢?

缩容比扩容慢得多!为什么?

原因 1: 稳定窗口(Stabilization Window)

yaml 复制代码
behavior:
  scaleDown:
    stabilizationWindowSeconds: 300  # 5 分钟
  • HPA 会观察过去 5 分钟内的最高指标值
  • 只有持续 5 分钟低于目标,才会缩容
  • 防止频繁抖动

原因 2: 保守的缩容策略

yaml 复制代码
policies:
- type: Pods
  value: 1              # 每次只减 1 个
  periodSeconds: 60     # 每 60 秒
  • 每分钟最多缩减 1 个 Pod
  • 从 4 → 2 需要 2 分钟(还要加上稳定窗口)

为什么要这样设计?

复制代码
场景 1:快速扩容
- 流量突增 → 服务卡顿 → 用户流失
- 影响:严重!
- 策略:立即扩容(0 秒稳定窗口)

场景 2:快速缩容
- 流量短暂下降 → 立即缩容 → 流量再次上升 → 又要扩容
- 影响:频繁抖动,浪费资源
- 策略:缓慢缩容(5 分钟稳定窗口)

设计原则

宁可多保留一会儿 Pod(多花点钱)
也不能让服务卡顿(影响用户体验)


六、HPA 行为策略详解

6.1 ScaleUp 策略

策略 1:百分比策略

yaml 复制代码
scaleUp:
  policies:
  - type: Percent
    value: 50          # 增加 50%
    periodSeconds: 60

举例

复制代码
当前: 4 个 Pod
策略: 50% 每 60 秒
计算: 4 × 50% = 2
结果: 每分钟最多增加 2 个 Pod

策略 2:绝对数量策略

yaml 复制代码
scaleUp:
  policies:
  - type: Pods
    value: 3           # 增加 3 个
    periodSeconds: 60

举例

复制代码
当前: 2 个 Pod
策略: +3 每 60 秒
结果: 每分钟最多增加 3 个 Pod

策略 3:组合策略

yaml 复制代码
scaleUp:
  policies:
  - type: Percent
    value: 100         # 翻倍
    periodSeconds: 15
  - type: Pods
    value: 4           # 或者 +4
    periodSeconds: 15
  selectPolicy: Max    # 选择更激进的

举例

复制代码
当前: 3 个 Pod
策略 1(翻倍): 3 × 100% = 3 → 总共 6 个
策略 2(+4): 3 + 4 = 7 个
selectPolicy: Max → 选择 7 个

6.2 ScaleDown 策略

保守策略(推荐)

yaml 复制代码
scaleDown:
  stabilizationWindowSeconds: 300  # 5 分钟
  policies:
  - type: Pods
    value: 1                       # 每次 -1
    periodSeconds: 60              # 每分钟
  selectPolicy: Min                # 保守

激进策略(不推荐)

yaml 复制代码
scaleDown:
  stabilizationWindowSeconds: 60   # 仅 1 分钟
  policies:
  - type: Percent
    value: 50                      # 减半
    periodSeconds: 30
  selectPolicy: Max                # 激进

为什么不推荐激进缩容?

  • 容易导致频繁抖动
  • 用户体验差(响应时间忽快忽慢)
  • 反而浪费资源(不断创建/删除 Pod)

6.3 稳定窗口的作用

没有稳定窗口的问题

复制代码
16:00  流量高 → CPU 80% → 扩到 6 个
16:02  流量降 → CPU 40% → 缩到 3 个
16:04  流量高 → CPU 80% → 扩到 6 个
16:06  流量降 → CPU 40% → 缩到 3 个
...    不断抖动!

有稳定窗口(5 分钟)

复制代码
16:00  流量高 → CPU 80% → 扩到 6 个
16:02  流量降 → CPU 40% → 开始观察
16:03  流量高 → CPU 70% → 取消缩容
16:05  流量降 → CPU 40% → 开始观察
16:10  持续低负载 5 分钟 → 缩到 3 个

稳定窗口算法

复制代码
HPA 在决定缩容时,会查看过去 N 秒的历史指标
取其中的最大值进行计算

例如:稳定窗口 = 300 秒
16:10 时的指标历史:
- 16:05: 40%
- 16:06: 50%  ← 最大值
- 16:07: 45%
- 16:08: 42%
- 16:09: 40%
- 16:10: 38%

计算时使用: 50%(最大值)
只有当 50% < 70% 且持续 5 分钟,才缩容

6.4 策略组合示例

场景 1:电商秒杀(快速扩容,慢速缩容)

yaml 复制代码
behavior:
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 200             # 可以 3 倍扩容
      periodSeconds: 15
    - type: Pods
      value: 10              # 或者直接 +10
      periodSeconds: 15
    selectPolicy: Max
  
  scaleDown:
    stabilizationWindowSeconds: 600  # 10 分钟
    policies:
    - type: Pods
      value: 1
      periodSeconds: 120     # 每 2 分钟 -1
    selectPolicy: Min

场景 2:夜间定时任务(允许快速缩容)

yaml 复制代码
behavior:
  scaleUp:
    stabilizationWindowSeconds: 30
    policies:
    - type: Pods
      value: 5
      periodSeconds: 60
  
  scaleDown:
    stabilizationWindowSeconds: 60   # 仅 1 分钟
    policies:
    - type: Percent
      value: 50              # 可以快速减半
      periodSeconds: 30

七、多指标 HPA 配置

7.1 CPU + 内存双指标

yaml 复制代码
metrics:
# CPU 指标
- type: Resource
  resource:
    name: cpu
    target:
      type: Utilization
      averageUtilization: 70

# 内存指标
- type: Resource
  resource:
    name: memory
    target:
      type: Utilization
      averageUtilization: 80

7.2 多指标计算逻辑

HPA 会为每个指标单独计算期望副本数,然后取最大值。

示例

复制代码
当前副本数: 2

指标 1 - CPU:
- 当前: 50%
- 目标: 70%
- 计算: ceil(2 × 50% / 70%) = 2

指标 2 - 内存:
- 当前: 85%
- 目标: 80%
- 计算: ceil(2 × 85% / 80%) = 3

最终结果: max(2, 3) = 3 个副本

逻辑

复制代码
期望副本数 = MAX(
  根据 CPU 计算的副本数,
  根据内存计算的副本数,
  ...其他指标
)

为什么取最大值?

  • 确保所有指标都满足
  • 避免某个指标超限

7.3 指标优先级

问题:CPU 和内存哪个更重要?

yaml 复制代码
# ❌ 错误:只配置 CPU
metrics:
- type: Resource
  resource:
    name: cpu
    target:
      averageUtilization: 70

# 问题:内存可能达到 100%,导致 OOMKilled
yaml 复制代码
# ✅ 正确:同时配置 CPU 和内存
metrics:
- type: Resource
  resource:
    name: cpu
    target:
      averageUtilization: 70
- type: Resource
  resource:
    name: memory
    target:
      averageUtilization: 80

# 任何一个超标都会触发扩容

建议

  • 始终配置 CPU 和内存双指标
  • CPU 阈值:60-70%
  • 内存阈值:70-80%(留更多 buffer)

八、HPA 调优技巧

8.1 如何让 HPA 更敏感?

降低目标利用率

yaml 复制代码
# 更敏感(容易触发扩容)
metrics:
- type: Resource
  resource:
    name: cpu
    target:
      averageUtilization: 50  # 降低到 50%

效果

  • CPU 超过 50% 就扩容
  • 更早响应负载变化
  • 但会增加资源成本

降低 requests

yaml 复制代码
resources:
  requests:
    cpu: "50m"     # 降低 requests
  limits:
    cpu: "500m"    # limits 不变

效果

  • 利用率 = 实际使用 / requests
  • requests 越小,利用率越容易超标
  • 更容易触发 HPA

8.2 如何避免频繁抖动?

增加稳定窗口

yaml 复制代码
behavior:
  scaleDown:
    stabilizationWindowSeconds: 600  # 增加到 10 分钟

增加缩容间隔

yaml 复制代码
behavior:
  scaleDown:
    policies:
    - type: Pods
      value: 1
      periodSeconds: 120  # 增加到 2 分钟

增加 minReplicas

yaml 复制代码
spec:
  minReplicas: 3  # 提高最小值
  maxReplicas: 10

效果

  • 保持更多 Pod,减少缩容次数
  • 更好的抗冲击能力

8.3 如何快速扩容、缓慢缩容?

这是最佳实践!

yaml 复制代码
behavior:
  scaleUp:
    stabilizationWindowSeconds: 0     # 立即扩容
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15                # 快速翻倍
    selectPolicy: Max
  
  scaleDown:
    stabilizationWindowSeconds: 300   # 5 分钟观察
    policies:
    - type: Pods
      value: 1
      periodSeconds: 60                # 缓慢缩容
    selectPolicy: Min

原理

  • 扩容影响用户体验 → 必须快
  • 缩容只影响成本 → 可以慢

8.4 如何设置合理的阈值?

经验值表

应用类型 CPU 阈值 内存阈值 原因
API 服务 60-70% 70-80% 平衡性能和成本
计算密集型 70-80% 60-70% CPU 是瓶颈
内存密集型 50-60% 70-80% 内存是瓶颈,要留 buffer
关键业务 50-60% 60-70% 性能优先
非关键业务 70-80% 80-90% 成本优先

测试方法

  1. 先设置保守值(50%/60%)
  2. 压测观察
  3. 逐步提高阈值
  4. 找到性能和成本的平衡点

九、常见问题排查

9.1 HPA 不工作

现象:负载很高,但 HPA 不扩容

排查步骤

bash 复制代码
# 1. 检查 HPA 状态
kubectl describe hpa cloudnative-api-hpa

# 查看 Conditions 部分:
# - AbleToScale: 是否可以扩缩容
# - ScalingActive: 指标是否有效
# - ScalingLimited: 是否达到上限

常见原因

原因 1:已达到 maxReplicas

复制代码
ScalingLimited  True  TooManyReplicas  the desired replica count is more than the maximum replica count

解决:增加 maxReplicas

原因 2:Pod 无 resources.requests

复制代码
ScalingActive  False  FailedGetResourceMetric  missing request for cpu

解决:在 Deployment 中添加 resources.requests

原因 3:Metrics Server 问题

复制代码
ScalingActive  False  FailedGetResourceMetric  unable to get metrics for resource cpu

解决:检查并修复 Metrics Server

9.2 HPA 显示 unknown

见本文 [3.4 我踩的坑:TARGETS 显示 unknown](#3.4 我踩的坑:TARGETS 显示 unknown)

9.3 HPA 扩容太慢

原因分析

  1. Metrics 采集延迟(15 秒)
  2. HPA 检查间隔(15 秒)
  3. Pod 启动时间(10-30 秒)

优化方案

方案 1:降低阈值

yaml 复制代码
metrics:
- type: Resource
  resource:
    name: cpu
    target:
      averageUtilization: 50  # 降低阈值

方案 2:激进的扩容策略

yaml 复制代码
behavior:
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 200     # 可以 3 倍扩容
      periodSeconds: 15

方案 3:提高 minReplicas

yaml 复制代码
spec:
  minReplicas: 5   # 保持更多 Pod

9.4 HPA 频繁抖动

现象:副本数不断变化(2 → 4 → 2 → 4)

原因

  • 稳定窗口太短
  • 缩容策略太激进
  • 阈值设置不合理

解决方案

yaml 复制代码
behavior:
  scaleDown:
    stabilizationWindowSeconds: 600  # 增加到 10 分钟
    policies:
    - type: Pods
      value: 1
      periodSeconds: 120  # 每 2 分钟 -1

9.5 Pod 被 OOMKilled

现象:扩容过程中,Pod 突然被杀

bash 复制代码
kubectl describe pod cloudnative-api-xxx
# 查看 Events:
# OOMKilled  Container cloudnative-api was killed due to OOM

原因:内存 limits 太小

解决

yaml 复制代码
resources:
  requests:
    memory: "128Mi"
  limits:
    memory: "512Mi"  # 提高 limits(原来 256Mi)

结语

这篇文章中,我深入学习了 HPA 的配置和实战:

✅ 我学到了什么

  1. HPA 核心原理

    • 计算公式:期望副本数 = 当前副本数 × (当前指标 / 目标指标)
    • 多指标取最大值
    • 每 15 秒检查一次
  2. HPA 配置详解

    • scaleTargetRef:控制目标
    • metrics:扩缩容指标(CPU、内存)
    • behavior:扩缩容策略
    • minReplicas/maxReplicas:范围控制
  3. Behavior 策略

    • scaleUp:快速响应(0 秒稳定窗口)
    • scaleDown:保守缩容(300 秒稳定窗口)
    • 稳定窗口防止抖动
  4. 扩缩容过程

    • 扩容:30-40 秒
    • 缩容:5+ 分钟
    • 扩容快、缩容慢是最佳实践
  5. 调优技巧

    • 降低阈值 → 更敏感
    • 增加稳定窗口 → 避免抖动
    • CPU 60-70%, 内存 70-80%
    • 始终配置双指标
  6. 常见问题

    • unknown → Metrics Server 或 requests 问题
    • 不扩容 → 达到上限或指标无效
    • 频繁抖动 → 缩容策略太激进

🎯 实战成果

  • ✅ 成功配置 HPA
  • ✅ 观察到自动扩容(2 → 4)
  • ✅ 观察到自动缩容(4 → 2)
  • ✅ 理解并优化 behavior 策略
  • ✅ 掌握问题排查方法

🚀 下一步

下一篇文章,我会:

  • ✅ 使用 k6 进行专业的压测
  • ✅ 验证 HPA 在真实负载下的表现
  • ✅ 分析性能指标和扩缩容效果
  • ✅ 给出完整的性能报告

敬请期待《压测实战:验证弹性伸缩效果》!


相关文章

项目代码GitHub - cloudnative-go-journey

相关推荐
不爱笑的良田8 小时前
从零开始的云原生之旅(九):云原生的核心优势:自动弹性伸缩实战
云原生·容器·kubernetes·go
万岳科技程序员小金8 小时前
多商户商城APP源码开发的未来方向:云原生、电商中台与智能客服
人工智能·云原生·开源·软件开发·app开发·多商户商城系统源码·多商户商城app开发
lijun_xiao20098 小时前
DevOps(devops/k8s/docker/Linux)学习笔记-2
docker·kubernetes·devops
pedestrian_h10 小时前
docker快速上手笔记
笔记·docker·容器
掘根11 小时前
【Docker】容器操作和实战
运维·docker·容器
奔跑吧 android14 小时前
【Docker】【2.docker 安装 ubuntu 桌面版】
ubuntu·docker·容器
头发那是一根不剩了15 小时前
Docker Desktop 安装教程和最佳实践
运维·docker·容器
白小云<16 小时前
Kubernetes service管理
云原生·容器·kubernetes
tianyuanwo17 小时前
K8s Dashboard运维技巧全面经验总结
linux·运维·kubernetes