很多团队把 HPA 绑在 CPU 和内存上跑了大半年,某天流量突然打个喷嚏,Pod 还没来得及扩容,请求队列已经先崩了。原因不复杂——CPU 的负载上升往往滞后于流量冲击,等指标越过阈值,响应延迟早已不可接受。自定义指标要填补的,正是这段“反应时差”。
用什么样的指标才有意义
选指标这件事,要先分清是流量型瓶颈还是资源型瓶颈。面向用户的服务,首选的通常是请求速率(RPS)或者 P95/P99 延迟;消息队列消费者则更适合用积压量(queue depth)作为弹性依据。还有一种容易忽略的场景——业务逻辑自身的“饱和信号”,比如某个线程池活跃数、内部令牌消耗率,这些指标远比 CPU 更贴近服务是否真的要撑不住了。
指标确定后,后续所有调优都围绕一个核心公式运转:期望副本数 = 当前指标值 ÷ 阈值。这意味着阈值设定非常关键。阈值太低会频繁扩容浪费成本,太高则始终在延迟边沿试探。拿 RPS 举例,单个 Pod 的压测极值是 500 rps,直接设 450 会让缓冲空间不足,设为 350 又可能引起过度扩容。实践中往往取极限值的 70% 并在此基础上压测校准,确保扩容触发时,单 Pod 实际负载没有堆积大量未处理请求。
让 Kubernetes 看见你的指标
内置的 metrics-server 只提供 CPU/内存,自定义指标需要一套适配层。业界最成熟的组合是 Prometheus + Prometheus Adapter,后者把 PromQL 查询结果转化成 Kubernetes 自定义指标 API。配置要点有两个:一是声明指标发现规则(seriesQuery),二是定义如何将 Prometheus 标签映射为 Kubernetes 资源对象(metricsQuery)。草草映射很容易出现“指标存在但 HPA 获取为 0”的灵异事件——通常是因为 namespace 或 pod 标签对应关系写错了。
另一个潜在坑是目标类型。Pods 指标会按每个 Pod 的平均值计算,适用于“每个副本正在处理多少请求”的场景;Object 指标则针对某个服务级别的对象(比如 Ingress 的总 QPS)与副本数做除法。选错类型,HPA 的计算逻辑就会跑偏。
把准弹性节奏
光有指标还不够,HPA 的 behavior 配置决定了实际效果是“丝滑”还是“抽风”。扩容需要零冷却窗口(stabilizationWindowSeconds: 0),让副本数尽快跟上突发流量;但缩容必须加一个至少两三分钟的观望期,防止指标瞬时回落就误杀 Pod。策略上,扩容用 Percent 模式(比如每次增加当前副本数的 100%),能快速翻倍;缩容用固定步长(比如一次最多减 2 个),避免砍得过猛导致处理能力陡降。
还有个血泪教训:不要只盯着自定义指标就完全弃用 CPU/内存。保留一条基于资源利用率的兜底规则,可以防止自定义指标采集链路中断时 HPA 彻底“失明”。两条规则取最大值扩容,取最小值缩容,这样才算给生产环境上了双保险。
真正落到生产的自定义 HPA,从来不是写个 YAML 就完事的。它需要持续观察“扩容触发点是否真正早于故障”,并结合压测数据反复调参。这一轮打磨下来,服务不再被动地等 CPU 飙红,而是直接听业务信号的脉搏。

搞了大半年CPU HPA,确实坑不少,自定义指标才是正道
P95延迟怎么采集啊,得装啥组件?
阈值设70%是经验值,还得看业务抖动幅度