K8s HPA:从配置到压测验证

HPA(Horizontal Pod Autoscaler)是 K8s 的弹性伸缩:CPU 高了加 Pod,低了减 Pod。配置起来 10 分钟,但"弹性到底灵不灵“要踩完坑才知道。这篇文章是完整实战。

一、最小配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: delivery-service
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: delivery-service
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60

含义:CPU 平均使用率超 60% 就扩容,低于再缩容,范围 2-10 副本。

二、核心机制:怎么算的

期望副本数公式

期 例 期 望 : 望 副 当 副 本 前 本 = 2 = c 副 c e 本 e i , i l 平 l ( 均 ( 当 2 前 C 副 P × 本 U 9 × 9 0 0 当 % / 前 , 指 目 6 标 标 0 ) / 6 0 = 目 % 标 c 指 e 标 i ) l ( 3 ) = 3 个

两个关键窗口

参数 默认 说明
--horizontal-pod-autoscaler-sync-period 15s 指标采集周期
--horizontal-pod-autoscaler-cpu-initialization-period 5m Pod 启动 5 分钟内不参与指标计算

坑:扩容要等指标周期 + 决策周期,不会瞬间加 Pod——压测时"打了 30 秒才有反应"是正常的。

三、HPA 的坑(实战记录)

坑 1:只配 CPU 不够,QPS 高峰 CPU 不高

我们的简历服务是 IO 密集型(大量 ES 调用),CPU 一直 30%,但 QPS 翻倍时延迟暴涨——CPU 指标根本不触发扩容。

解法:自定义指标(QPS 或 P99 延迟):

1
2
3
4
5
6
7
8
metrics:
- type: Pods
  pods:
    metric:
      name: http_requests_per_second
    target:
      type: AverageValue
      averageValue: 200   # 每 Pod 超 200 QPS 扩容

需要 Prometheus Adapter 把业务指标暴露给 HPA:

P r o → → m e p H t r P h o A e m u e 读 s t 取 h 采 e → 集 u s 触 h - 发 t a 伸 t d 缩 p a _ p r t e e q r u ( e c s u t s s t _ o t m o t m a e l t r i c s A P I )

坑 2:扩容慢、缩容快是错觉

默认行为:

  • 扩容:只要超过目标,立即扩(每次翻倍 +1)
  • 缩容:--horizontal-pod-autoscaler-downscale-stabilization-window 默认 5 分钟——指标低于目标后要等 5 分钟才缩

这是设计:防止抖动(流量一会高一会低疯狂增删 Pod)。但高峰期突然腰斩时,5 分钟缩容太慢,浪费钱:

1
2
kube-controller-manager:
  --horizontal-pod-autoscaler-downscale-stabilization-window=3m

坑 3:Pod 启动慢导致伸缩震荡

服务启动要 40s(加载配置、预热缓存),HPA 看到 CPU 低就缩容,刚缩完流量来了又扩——震荡。

解法:

  1. readinessProbe 就绪才接流量(HPA 只统计就绪 Pod)
  2. initialDelaySeconds 给足启动时间
  3. 业务层:扩容预留缓冲(minReplicas 别设 1,至少 2-3)

坑 4:单实例指标抖动

Pod 数少时,一个 Pod 的 GC/慢请求会把平均指标拉爆,误扩容。

解法:指标聚合窗口拉长(Prometheus 用 5m rate 而不是瞬时值)。

四、压测验证:弹性到底灵不灵

配置完必须压测验证,我的标准流程:

1
2
3
4
5
6
# 1. 用 k6/wrk 打流量,从 100 QPS 线性升到 2000
k6 run --vus 200 --duration 5m load.js

# 2. 同时观察:
kubectl get hpa delivery-service -w      # 看副本数变化
kubectl top pods                         # 看实际资源

验收标准:

✅ ✅ ✅ ✅ 流 扩 流 全 量 容 量 程 升 后 降 无 到 后 阈 P , 5 值 9 副 x 后 9 本 x , 数 副 延 在 持 本 迟 稳 续 数 回 定 ( 在 落 窗 扩 ( 口 容 2 服 后 滞 - 务 回 后 5 恢 缩 期 复 允 分 ) 许 钟 短 内 暂 升 ) 到 预 期

五、最佳实践清单

✅ ✅ ✅ ✅ ✅ ✅ 多 m 扩 启 缩 定 指 i 容 动 容 期 标 n 上 探 稳 压 : R 限 针 定 测 C e 考 就 窗 验 P p 虑 绪 口 证 U l 下 才 ( i 游 接 3 每 + c : 流 - 次 a D 量 5 发 Q s B 版 P / 分 后 S 留 E 钟 重 缓 S 跑 双 冲 ) 指 ( 连 标 至 接 ( 少 数 业 上 务 2 限 指 , 决 标 防 定 更 止 贴 缩 m 真 到 a 实 底 x 负 ) R 载 e ) p l i c a s

maxReplicas 别拍脑袋:扩到 20 个 Pod,数据库连接池扛得住吗?扩容是系统性的,不只是 K8s 的事。

总结

HPA 的核心认知:

  1. CPU 指标只对计算型服务有效,IO 型/业务型要配自定义指标
  2. 伸缩不是即时的,指标周期 + 稳定窗口,别期望秒级响应
  3. 震荡是头号敌人:探针就绪 + 缓冲副本 + 稳定窗口
  4. 压测验证:不压测的 HPA 配置等于没配

弹性伸缩的终点不是"能扩”,是"扩得及时、缩得稳定、下游扛得住"。