尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

K8s HPA扩缩容震荡复盘:CPU阈值配错后,服务在凌晨被扩缩了47次

K8s HPA扩缩容震荡复盘:CPU阈值配错后,服务在凌晨被扩缩了47次
📅 发布时间:2026/7/9 14:16:28

K8s HPA扩缩容震荡复盘:CPU阈值配错后,服务在凌晨被扩缩了47次

凌晨3点被告警电话叫醒,打开监控面板差点没背过气去:Deployment的Pod数量在10分钟里从3个飙到47个,又缩回3个,来回震荡了5轮。CPU使用率曲线像心电图,Pod重建次数直接刷屏。

事情的罪魁祸首,居然是HPA里两个阈值的配法。


背景:一个看似正常的HPA配置

我们有一个核心的订单处理服务,平时3个Pod就能扛住流量。为了应对早晚高峰,我给它配了HPA(Horizontal Pod Autoscaler),目标是在CPU使用率超过70%时自动扩容,低于30%时缩容。

当时的配置看起来挺合理的:

apiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:order-service-hpaspec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:order-serviceminReplicas:3maxReplicas:50metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:70behavior:scaleDown:stabilizationWindowSeconds:60policies:-type:Percentvalue:50periodSeconds:60scaleUp:stabilizationWindowSeconds:0policies:-type:Percentvalue:100periodSeconds:15

问题出在哪?

扩容和缩容的阈值差距太大了。70%扩,30%缩,中间差了40个百分点。当Pod从3个扩容到6个后,CPU使用率会立刻掉一半(如果负载没变的话),直接从70%掉到35%左右。然后HPA一看:35%低于30%?不,还没到。但如果负载稍微波动一下,掉到28%,缩容触发,Pod从6个缩回3个。CPU使用率又飙回70%,扩容再次触发。

就这样,我们在凌晨3点见证了一场完美的"扩缩容震荡"。


排查时间线:20分钟定位根因

3:12 告警触发

Prometheus告警规则:kube_deployment_status_replicas_unavailable > 0连续3分钟触发。同时收到k8s_hpa_desired_replicas > 20的告警。

打开Grafana,看到 Pod 数量曲线:

3:05 → 3 replicas 3:07 → 6 replicas 3:08 → 12 replicas 3:09 → 24 replicas 3:10 → 47 replicas(达到maxReplicas上限) 3:11 → 24 replicas 3:12 → 12 replicas ...(震荡继续)
3:15 确认不是流量攻击

先排查是不是突发流量。看 ingress-nginx 的 QPS 面板,凌晨3点流量平稳,比平时还低。排除流量突增导致。

3:18 定位HPA行为异常

执行kubectl describe hpa order-service-hpa,看到事件日志刷屏:

Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 10s horizontal-pod-autoscaler New size: 6; reason: cpu resource utilization (percentage) above target Normal SuccessfulRescale 15s horizontal-pod-autoscaler New size: 12; reason: cpu resource utilization (percentage) above target Normal SuccessfulRescale 20s horizontal-pod-autoscaler New size: 24; reason: cpu resource utilization (percentage) above target Normal SuccessfulRescale 30s horizontal-pod-autoscaler New size: 3; reason: All metrics below target Normal SuccessfulRescale 35s horizontal-pod-autoscaler New size: 6; reason: cpu resource utilization (percentage) above target

All metrics below target和above target交替出现,间隔只有5秒。这就是典型的扩缩容震荡。

3:22 检查HPA配置,发现阈值问题

用kubectl get hpa order-service-hpa -o yaml导出配置,一眼看到问题:

averageUtilization:70# 扩容阈值

缩容默认行为没有显式配置目标值,但默认是50%?不,K8s HPA的缩容并没有单独的阈值。它用的是同一个目标值:70%。也就是说,当使用率低于70%时,理论上都可能触发缩容。但HPA的缩容有冷却窗口(stabilizationWindowSeconds),默认是5分钟。

等等,我配置了scaleDown.stabilizationWindowSeconds: 60,只有1分钟。这意味着扩容后只要CPU在1分钟内低于目标值,就会缩容。而CPU在扩容后通常会骤降,加上 Pod 启动和就绪探针的延迟,实际使用率计算时会出现短暂低于目标的情况。

根本原因是:扩缩容阈值重叠 + 缩容冷却窗口太短 + 没有设置缩容的 targetUtilization 下限。


修复方案:三层加固

第一层:调整目标值,增加缓冲区

核心修复:把HPA的CPU目标从70%改为85%,同时引入自定义指标(请求延迟)作为辅助判断,避免单一指标导致震荡。

apiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:order-service-hpaspec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:order-serviceminReplicas:3maxReplicas:50metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:85# 提高扩容阈值,给缓冲区-type:Podspods:metric:name:http_request_duration_seconds_p99target:type:AverageValueaverageValue:"500m"# P99延迟超过500ms才扩容behavior:scaleDown:stabilizationWindowSeconds:300# 缩容冷却窗口延长到5分钟policies:-type:Percentvalue:10# 每次缩容最多10%periodSeconds:60scaleUp:stabilizationWindowSeconds:0policies:-type:Percentvalue:100periodSeconds:15-type:Podsvalue:4periodSeconds:15selectPolicy:Max

关键改动:

  • CPU目标从70%提到85%:减少扩容的敏感度,避免轻微波动就触发扩容。
  • 缩容冷却窗口从60秒延长到300秒:确保扩容后的稳定期足够长,让Pod充分承载负载。
  • 缩容策略改为每次最多10%:避免一次性缩回太多Pod,导致CPU反弹。
  • 引入P99延迟作为辅助指标:CPU可能受JVM GC、定时任务等影响波动,但延迟更能反映真实服务质量。
第二层:给Pod加上启动期和就绪期保护

Pod刚启动时CPU使用率会短暂飙升(JVM预热、连接池初始化),这会导致HPA误判。加上startupProbe和适当的initialDelaySeconds:

apiVersion:apps/v1kind:Deploymentmetadata:name:order-servicespec:template:spec:containers:-name:order-serviceimage:order-service:v2.3.1resources:requests:cpu:"500m"memory:"1Gi"limits:cpu:"1000m"memory:"2Gi"startupProbe:httpGet:path:/actuator/healthport:8080initialDelaySeconds:10periodSeconds:5failureThreshold:12# 最多60秒启动时间readinessProbe:httpGet:path:/actuator/health/readinessport:8080initialDelaySeconds:5periodSeconds:5failureThreshold:3livenessProbe:httpGet:path:/actuator/health/livenessport:8080initialDelaySeconds:30periodSeconds:10failureThreshold:3

划重点:HPA计算CPU使用率时,只统计Ready状态的Pod。如果Pod还在Startup阶段,不会被纳入计算。所以合理的启动探针能避免"未就绪Pod拖累平均值"的问题。

第三层:监控告警和应急预案

加了两个Prometheus告警规则,专门监控HPA震荡:

-alert:HPAFlappingDetectedexpr:|( count by (namespace, horizontalpodautoscaler) ( kube_horizontalpodautoscaler_status_condition{status="True", condition="ScalingLimited"} == 1 ) > 0 and count by (namespace, horizontalpodautoscaler) ( changes(kube_horizontalpodautoscaler_status_current_replicas[10m]) > 5 ) > 0 )for:2mlabels:severity:criticalannotations:summary:"HPA {{ $labels.horizontalpodautoscaler }} 震荡检测"description:"10分钟内副本数变化超过5次,疑似扩缩容震荡"-alert:HPAScaleToMaxexpr:|kube_horizontalpodautoscaler_status_current_replicas / kube_horizontalpodautoscaler_spec_max_replicas == 1for:5mlabels:severity:warningannotations:summary:"HPA {{ $labels.horizontalpodautoscaler }} 已达到最大副本数"description:"当前副本数等于maxReplicas,可能需要扩容上限或排查异常"

应急预案:如果HPA震荡发生,快速执行kubectl scale deployment order-service --replicas=5固定副本数,然后手动调整HPA配置。


踩坑记录:HPA的4个血泪教训

1. 不要用默认的scaleDown配置

K8s HPA的默认缩容冷却窗口是5分钟(300秒),但默认缩容策略是每分钟缩容当前副本数的100%——这意味着只要条件满足,它可以在1分钟内把所有Pod都缩掉。生产环境务必显式配置behavior.scaleDown。

2. CPU目标值不是越低越好

很多人觉得CPU使用率超过50%就该扩容,但其实要考虑服务的负载特征。如果服务有定期任务(比如每5分钟跑一次统计),CPU会周期性波动。目标值设太低,这些正常波动也会触发扩容。对于Web服务,CPU目标在70%-85%通常比较合理。

3. HPA的CPU计算包含所有Ready Pod,但metric-server采样有延迟

metric-server默认每15秒采集一次CPU使用率,而HPA每15秒评估一次。如果Pod刚启动,CPU采样可能还没稳定。加上启动探针和适当的initialDelay,能避免"新Pod拉高平均值"或"新Pod还没数据被跳过"的问题。

4. 单一指标很容易翻车

只依赖CPU的HPA,在遇到GC、定时任务、批处理作业等场景时很容易误判。建议至少搭配一个业务指标(比如QPS、延迟、队列深度)或者自定义的external metrics。


写在最后

这次凌晨3点的故障,表面上是HPA配置的问题,本质上是对自动扩缩容的理解还不够深。K8s HPA看似简单,但target utilization、stabilization window、behavior policies这几个参数组合起来,能在生产环境玩出各种花样。

修复后监控了一周,HPA行为稳定。早高峰从3个Pod扩容到8个,耗时约90秒;晚高峰结束后,缩容到5个Pod(不是直接缩回3个),然后平稳过渡到3个。再也没有出现过震荡。

如果你也在用HPA,建议检查一下:

  1. 你的缩容冷却窗口是不是太短了?
  2. 你的CPU目标值有没有给服务留够缓冲区?
  3. 有没有只靠CPU一个指标在做扩缩容决策?

希望这篇复盘能帮你少走点弯路。有问题欢迎评论区交流。

相关新闻

  • MaxKB二次开发
  • 蓝牙5.4 LE Audio嵌入式开发实战
  • FModel技术解析:虚幻引擎游戏资产探索工具的价值定位与实现机制

最新新闻

  • 2026年最新河南兴宸机械制造有限公司燃烧器业务情况介绍 - 奔跑123
  • 工业信号干扰防护与FOD4216光耦应用实战
  • MOSFET漏源极过压保护方案对比:TVS、稳压管、RC缓冲3种方案实测与失效分析
  • 2026 执业药师备考避坑指南!3 家主流机构网课题库实测对比,药店人省钱高效选课攻略 - 优学考证上岸
  • AI多因子预测模型:油价涨逾5%压制黄金,金价冲高回落的Transformer分析框架
  • 最新3-5吨高精密伺服压机口碑好供应商全维度测评 - 信息热点

日新闻

  • SQL 查询语句的标准逻辑执行顺序(即语义处理顺序),它与实际书写顺序不同,但决定了数据库如何解析和执行查询
  • ORB-SLAM2 重定位模块深度解析:从 BoW 候选帧到 PnP 优化的 6 步流程
  • 罗技鼠标宏压枪脚本终极指南:从原理到实战的完整解析

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号