我不会起名字322· 后端 / 算法 / 数据库
📘 技术栈 | 🧩 力扣 Hot100 | 🐹 Go 项目 | 🟥 Redis | 🐬 MySQL
文章目录
- HPA 不扩容:metrics-server 与指标延迟的 3 个原因
- 一、先看 HPA 自己怎么说
- 二、原因 1:Pod 没设 CPU request
- 三、原因 2:metrics-server 本身有问题
- 先确认它活着
- 最常见:拿不到指标
- 一个关键的延迟账
- 四、原因 3:稳定窗口与扩缩容策略把它按住了
- 机制 1:稳定窗口(stabilization window)
- 机制 2:`behavior` 里的速率限制
- 机制 3:容忍度(tolerance)
- 五、基于自定义指标的 HPA
- 六、带走物
HPA 不扩容:metrics-server 与指标延迟的 3 个原因
一、先看 HPA 自己怎么说
排查 HPA 不扩容,第一步永远是看它的Conditions——HPA 会把"为什么不扩"直接写在这里:
kubectl describe hpa<name>-n<ns>Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 3 ScalingActive False FailedGetResourceMetric the HPA was unable to compute the replica count: failed to get cpu utilization: missing request for cpu ScalingLimited True TooFewReplicas the desired replica count is more than the maximum replica count三个字段的读法:
| Type | 含义 | 常见 False 原因 |
|---|---|---|
AbleToScale | 能不能改副本数 | 被minReplicas/maxReplicas卡住、 stabilize 窗口内 |
ScalingActive | 能不能拿到指标 | metrics-server 挂了、Pod 没设 request |
ScalingLimited | 是否被上下限限制 | 期望副本数超过maxReplicas |
ScalingActive: False+FailedGetResourceMetric是最常见的一类,先看它。
二、原因 1:Pod 没设 CPU request
这是最高频的原因,而且报错信息很直白:
failed to get cpu utilization: missing request for cpuHPA 的 CPU 利用率是这么算的:
利用率 = 实际 CPU 使用量 / CPU request如果 Pod 没设resources.requests.cpu,分母就是 0,HPA 根本算不出百分比,于是拒绝扩容。
kubectl get pod<pod>-ojsonpath='{.spec.containers[*].resources}'# {} ← 空的就是没设修法:给所有会被 HPA 管理的容器都设 request。
resources:requests:cpu:200m# 必须有,HPA 的分母memory:256Mi注意是所有容器:如果 Pod 里有个 sidecar(比如日志采集、service mesh 的 envoy)没设 request,主容器的 request 也可能不被正确汇总——推荐用LimitRange给 namespace 设默认值,一劳永逸。
三、原因 2:metrics-server 本身有问题
先确认它活着
kubectl get pod-nkube-system|grepmetrics-server kubectl logs-nkube-system deploy/metrics-server--tail=50最常见:拿不到指标
kubectltopnodes# error: Metrics API not available或者:
kubectl get--raw/apis/metrics.k8s.io/v1beta1/nodes|headmetrics-server 不工作的几个典型原因:
(a) 没装。很多自建集群默认没有:
kubectl get apiservice v1beta1.metrics.k8s.io-oyaml|grep-A5conditions(b) kubelet 证书问题。最经典的错误是:
x509: cannot validate certificate for 10.0.1.20 because it doesn't contain any IP SANs解法是给 metrics-server 加启动参数:
args:---kubelet-insecure-tls# 测试环境可接受;生产应配好证书---kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP© 采集间隔太慢。metrics-server 默认--metric-resolution=15s(旧版 60s)。指标本身就有延迟。
一个关键的延迟账
HPA 从"负载升高"到"真的扩容",中间有几段延迟:
应用 CPU 升高 → metrics-server 采集(默认 15~60s) → HPA 控制器同步(默认 --horizontal-pod-autoscaler-sync-period=15s) → 判断是否连续满足条件(默认 5 分钟稳定窗口,扩容时通常更快) → 改 replicas → 新 Pod 调度 + 启动 + 就绪(几十秒到几分钟)加起来通常是 1~3 分钟,加上 Pod 冷启动可能 3~5 分钟。
这意味着:HPA 救不了秒级的突发流量。如果你的业务是秒级尖峰,HPA 来不及,需要预留 buffer 或者用 KEDA 这类基于队列长度/请求数的触发器。
四、原因 3:稳定窗口与扩缩容策略把它按住了
即使指标正常,HPA 也可能"故意不扩"。两个机制:
机制 1:稳定窗口(stabilization window)
默认缩容有 5 分钟的稳定窗口:HPA 会取最近 5 分钟里最大的期望副本数,防止抖动导致频繁缩容。
behavior:scaleDown:stabilizationWindowSeconds:300# 默认 300所以如果你刚经历了一波高峰又降下来,HPA 不会立刻缩——这是正常行为,不是 bug。
机制 2:behavior里的速率限制
K8s 1.18+ 支持自定义扩缩容速率:
behavior:scaleUp:stabilizationWindowSeconds:0policies:-type:Percentvalue:100periodSeconds:60# 每分钟最多扩一倍-type:Podsvalue:4periodSeconds:60# 或每分钟最多扩 4 个selectPolicy:MaxscaleDown:stabilizationWindowSeconds:300policies:-type:Percentvalue:100periodSeconds:60如果这里配得保守,指标超了也不会快速扩。检查:
kubectl get hpa<name>-oyaml|grep-A20behavior机制 3:容忍度(tolerance)
HPA 默认有10% 的容忍度:目标利用率 70%,实际在 63%~77% 之间时,HPA 认为"已经达标",不动。
这个不能通过配置改(硬编码),但要知道它的存在——所以别指望 HPA 把利用率精确控制在 70%。
五、基于自定义指标的 HPA
CPU 不总是合适的指标。比如一个消费者服务,CPU 一直很低但消息积压很高——这时应该用自定义指标(比如 Kafka lag)。
链路是:
应用暴露指标 → Prometheus 抓取 → prometheus-adapter 暴露成 custom.metrics.k8s.io → HPA 使用# 看有哪些自定义指标可用kubectl get--raw/apis/custom.metrics.k8s.io/v1beta1|jq'.resources[].name'|headHPA 配置:
apiVersion:autoscaling/v2kind:HorizontalPodAutoscalerspec:metrics:-type:Podspods:metric:name:kafka_consumer_lagtarget:type:AverageValueaverageValue:"1000"# 每个 Pod 平均积压 1000 条就扩自定义指标的延迟比 CPU 更大(多了一跳 Prometheus 抓取),调 stable window 时要考虑进去。
六、带走物
排查顺序:
# 1. HPA 自己说的理由(最重要)kubectl describe hpa<name>-n<ns>|grep-A8Conditions# 2. 指标能不能拿到kubectltoppods-n<ns>kubectl get--raw/apis/metrics.k8s.io/v1beta1/pods|head# 3. Pod 有没有 request(HPA 的分母)kubectl get pod-ojsonpath='{.spec.containers[*].resources}'# 4. metrics-server 活着吗kubectl logs-nkube-system deploy/metrics-server--tail=50# 5. 有没有被 behavior 限制kubectl get hpa<name>-oyaml|grep-A20behavior对应的三类修法:
| 原因 | 症状 | 修法 |
|---|---|---|
| 没设 request | missing request for cpu | 给所有容器设requests.cpu(用 LimitRange 兜底) |
| metrics-server 异常 | Metrics API not available、x509错误 | 检查 Pod/证书/--kubelet-insecure-tls |
| 稳定窗口/速率限制 | 指标正常但不扩 | 看behavior;缩容默认有 5 分钟窗口,属正常 |
一句话结论:HPA 不扩容时先看describe里的 Conditions,八成的原因写在那里;而"没设 request"和"metrics-server 挂了"这两条占了绝大多数。