11 | 弹性伸缩与 Serverless:用 HPA 让 AI 服务「峰谷自适应」

11 | 弹性伸缩与 Serverless:用 HPA 让 AI 服务「峰谷自适应」

11 | 弹性伸缩与 Serverless:用 HPA 让 AI 服务「峰谷自适应」

系列目录:《基于华为云 FlexusX 四节点集群的云计算全栈实操》PaaS 篇 · 收尾篇
本篇对应课程模块:弹性伸缩 / 云原生 Serverless 理念

引子

前两篇,我们把 K3s 集群建起来,又把情感分析推理服务部署上去,跑通了 4/4 正确分类。一切看起来很美——但有个问题没解决:服务是按固定副本数跑的

固定 3 副本意味着:流量小的时候,2 个 Pod 在空转烧钱;流量突增的时候,3 个 Pod 被打满、请求排队超时。这正是传统「买定离手」式容量规划的痛点。

云计算的终极承诺是按需付费、峰谷自适应——这就是 Serverless 的核心理念。本篇我们不讲抽象的 FaaS,而是用 Kubernetes 原生的HPA(Horizontal Pod Autoscaler,水平 Pod 自动伸缩),让上篇那个 AI 服务在压测时自动从 3 副本扩到 8 副本,负载消失后自动缩回 2 副本

这是整个系列的技术收尾,也是「云原生」四个字最直观的注脚。文末我还会用一段11 篇实战全景回顾,把从裸机到 Serverless 的整条链路串起来。


背景与理论:HPA 的闭环控制

《深入浅出云计算》把「弹性」列为云计算相对传统 IDC 的四大核心价值之一。在 K8s 里,弹性分三种:

弹性类型对象说明
HPA(水平)Pod 副本数加机器=加副本,本篇主角
VPA(垂直)单 Pod 资源加 CPU/内存,需重建 Pod
Cluster Autoscaler节点数副本不够时加节点(需对接云厂商)

HPA 是一个典型的负反馈闭环控制系统

┌──────────────┐ 指标 ┌──────────────────┐ │ metrics-server│◀────────│ 各 Pod 实时 CPU │ └──────┬───────┘ └──────────────────┘ │ 暴露指标 ▼ ┌──────────────┐ 比对 ┌──────────────────┐ │ HPA Controller│─────────│ 目标利用率 50% │ └──────┬───────┘ └──────────────────┘ │ 调节 replicas ▼ ┌──────────────┐ │ Deployment │ 期望副本 3 → 8 │ (ReplicaSet) │ └──────────────┘

工作原理一句话:metrics-server 采集 Pod 的 CPU/内存指标 → HPA 控制器周期性(默认 15s)比对「当前利用率」与「目标利用率」→ 按公式算出期望副本数 → 修改 Deployment 的 replicas。副本变了,调度器把新 Pod 排到各节点,流量自然被分摊。

HPA 副本数公式(简化):期望副本 = ceil(当前指标 / 目标指标)。当 CPU 实际 188%、目标 50%,即ceil(188/50)=4倍于当前负载基准——但受maxReplicas封顶,最终触顶到 8。

稳定窗口(stabilization window)是 HPA 防止「抖动」的关键:扩容快(默认无延迟或很短),缩容慢(默认 5 分钟)。否则流量一抖就缩,缩完又被打满,反复横跳。这 5 分钟,是工程上「宁多勿少」的权衡。


架构

metrics-server (采集 Pod CPU) │ ▼ HPA: sentiment-ai target=50% min=2 max=8 │ 调节 replicas ▼ Deployment 期望副本变化: 3 →(压测)→ 8 →(稳定窗口后)→ 2 │ ├── 新 Pod 调度到 node1/node3/node4(topologySpread 均衡) │ NodePort 30800 ── kube-proxy ──▶ 全部可用 Pod 分担流量 压测器: node1 后台 20 路并发 POST /predict 持续 90s

环境与准备

节点弹性公网IP私有IP规格系统K8s角色
node1113.47.6.41192.168.0.2528vCPU/16GiBUbuntu 24.04.4control-plane
node31.94.220.182192.168.0.2418vCPU/16GiBUbuntu 24.04.4worker
node4124.70.102.139192.168.0.1508vCPU/16GiBUbuntu 24.04.4worker

沿用前两篇集群。本篇新增依赖:metrics-server——K3s 默认未安装metrics-server(它内置的是轻量指标,但 HPA 需要标准 metrics.k8s.io API)。需先部署:

# 部署 metrics-server(国内可用阿里云镜像)kubectl apply-fhttps://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml# 若因证书问题无法采集,可临时加 --kubelet-insecure-tls(生产不建议长期开启)

验证指标可用:

kubectltopnodes kubectltoppods

注意:HPA 用的是 metrics-server 提供的metrics.k8s.io/v1beta1资源指标。CPU 利用率 = Pod 实际 CPU / Pod 的requests.cpu所以 Pod 必须配置resources.requests.cpu,否则 HPA 无法计算利用率(我们上篇已配requests.cpu: 100m)。


实操步骤

1. 创建 HPA

sentiment-ai配置:目标 CPU 50%,最小 2 副本、最大 8 副本:

kubectl autoscale deploy/sentiment-ai--cpu=50%--min=2--max=8

等价于下面这段 YAML(两种写法皆可):

apiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:sentiment-aispec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:sentiment-aiminReplicas:2maxReplicas:8metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:50behavior:scaleDown:stabilizationWindowSeconds:300# 默认 5 分钟稳定窗口

2. 压测前基线

先确认空闲状态——各节点 CPU 几乎为 0%,副本为 3:

kubectltopnodes kubectl get hpa

3. 施加负载

在 node1 后台发起20 路并发循环 POST /predict,持续 90 秒(用curl循环或hey/ab/k6均可):

# 简易压测(后台运行 90s)foriin$(seq120);do(whiletrue;docurl-s-XPOST http://127.0.0.1:30800/predict\-H'Content-Type: application/json'\-d'{"text":"this is absolutely wonderful, i love it"}'done)&donesleep90;killallcurl

4. 观察扩容

压测约 90 秒后,查看 HPA 状态。


真实输出(实测)

以下来自results/16_hpa_autoscale.txt

创建 HPA

$ kubectl autoscale deploy/sentiment-ai --cpu=50% --min=2 --max=8 horizontalpodautoscaler.autoscaling/sentiment-ai autoscaled

压测前基线

kubectl top nodes: ecs-71b9-0001 64m 0% ;ecs-71b9-0003 67m 0% ;ecs-71b9-0004 82m 1% REPLICAS: 3

空闲时三节点 CPU 利用率 0%~1%,副本 3——符合预期(此时尚未触发缩容到 min=2,因为 HPA 只在有负载偏差时调节;初始 3 副本在 [2,8] 区间内合法)。

压测中(约 90s 后自动扩容到上限)

NAME TARGETS MINPODS MAXPODS REPLICAS sentiment-ai cpu: 188%/50% 2 8 8 Pod 数量:8(跨 3 节点分布) ecs-71b9-0001 x3 ;ecs-71b9-0003 x3 ;ecs-71b9-0004 x2

CPU 利用率飙升到188%(远超 50% 目标),HPA 在约 1 分钟内把副本从 3 拉到8(触顶 max)。新副本自动跨 3 节点调度(node1×3、node3×3、node4×2,受 topologySpreadConstraints 约束大体均衡)。

结论(实测原文要点)

1. HPA 依据实时 CPU 指标(188% >> 50% 目标)在 ~1 分钟内将副本 3 -> 8(触顶 max) 2. 新副本自动跨节点调度,承接突发流量 3. 负载消失后,HPA 在默认 5 分钟稳定窗口后自动缩容回 min=2 4. 这正是 Serverless「按需弹性、峰谷自适应」的核心能力在 K8s 上的体现 (生产可进一步用 KEDA/Knative 实现请求驱动的 scale-to-zero)

深度解读:这就是 Serverless 的精髓

很多人把 Serverless 等同于「函数计算(FaaS)」,那是狭义理解。Serverless 的本质是「开发者不关心服务器,只关心代码/逻辑,按实际用量付费」。HPA 让我们看到了它的前半段:

  • 按需弹性:流量来了,副本自动涨;走了,自动降。你不用提前买好峰值容量。
  • 峰谷自适应:白天高峰 8 副本扛,半夜 2 副本歇着,资源不空转。

但与真正的 Serverless/FaaS还有一道鸿沟——scale-to-zero(缩容到零)

能力K8s HPA真 Serverless(Knative/KEDA/OpenFaaS)
扩容触发CPU/内存等指标HTTP 请求、消息队列、定时等事件驱动
缩容下限minReplicas: 1(至少留 1)可缩到0(无流量不占资源)
冷启动无(Pod 常驻)有(请求到来才拉起,需应对冷启延迟)
计费粒度按节点/Pod 常驻按实际调用次数/时长

HPA 的minReplicas最低是 1(即使设为 0,K8s 1.16+ 也支持 scaledown 到 0 但需特殊配置且少有人用)。要真正做到「无流量=零成本」,需要 KEDA(基于事件的驱动伸缩,支持缩到 0)或 Knative Serving(基于请求数,原生 scale-to-zero)

一句话总结本篇:HPA 是 K8s 上的「半 Serverless」——它解决了弹性伸缩,但还留着 1 个常驻 Pod;真正的Serverless 把那最后 1 个也省了,代价是冷启动延迟。选型时,延迟敏感选 HPA 常驻,成本极致选 KEDA/Knative。


踩坑与排障(重点)

坑 1:HPA 一直<unknown>/ 不生效

现象:kubectl get hpa显示TARGETS <unknown>/50%,副本不变。

根因(90% 概率):没装 metrics-server,或 Pod 没配resources.requests.cpu。HPA 算不出「利用率 = 实际/请求」,就无法决策。

排查:

kubectltoppods# 若报错,说明 metrics-server 没好kubectl get hpa-oyaml# 看 status.conditions 的 message

解决:装好 metrics-server,并确保 Deployment 里有requests.cpu

坑 2:扩容快、缩容慢,误以为「卡住」

压测一停,副本没立刻降——这是正常行为。HPA 默认缩容稳定窗口 5 分钟,目的是防止抖动。别手贱去手动scale,让控制器自己收。

坑 3:副本触顶 max 仍不够

本篇 CPU 188% 直接触顶 8,说明单 Pod 算力已是瓶颈。此时再怎么加副本也受限于节点总 CPU(3×8vCPU)。该上 Cluster Autoscaler 加节点,或优化模型/换更强实例规格,HPA 不是万能药。


生产建议与成本价值

容量规划的新范式:有了 HPA,你不再需要「按峰值买定」。按平均负载minReplicas,把maxReplicas交给突发。以本集群为例:

  • 平时 2~3 副本,约占 2~3 个 vCPU;
  • 大促/峰值自动顶到 8 副本,吃满约 8 个 vCPU;
  • 峰值过后 5 分钟自动回落。

成本价值:假设峰值每天只占 2 小时,固定 8 副本一年白烧 22 小时/天的算力;HPA 模式下这部分直接省掉——对长期运行的在线服务,弹性伸缩省下的钱相当可观。

生产加固清单

  1. 同时配 CPU + 内存 +(可选)QPS 多指标 HPA;
  2. maxReplicas要卡住,防止指标异常导致无限扩容把节点打爆;
  3. 配合PodDisruptionBudget防止缩容/驱逐时一次性干掉太多副本;
  4. 真正想 scale-to-zero,引入KEDA接 Kafka/HTTP/RabbitMQ 等事件源;
  5. 超大规模再上Cluster Autoscaler / Karpenter做节点级弹性。

11 篇实战全景回顾 + 云计算学习心得

写到这里,整个《基于华为云 FlexusX 四节点集群的云计算全栈实操》系列就完整了。回头看这 11 篇,是一条清晰的「由底向上」的云原生能力栈:

篇章主题核心收获
01~03云主机 / 网络 / 安全组四节点 FlexusX 基盘,VPC/安全组打通
04~05块存储 / 对象存储EVS 持久化、OBS 非结构化存储
06~07数据库 / 负载均衡RDS 托管库、ELB 流量入口
08监控告警CES 指标 + 阈值告警闭环
09K3s 多节点 K8s 集群容器编排四大能力(LB/自愈/伸缩/滚动更新)
10云上 AI 推理服务模型容器化、containerd 镜像交付、纯 CPU 推理
11HPA 弹性伸缩Serverless 式峰谷自适应(本篇)

几条贯穿始终的学习心得

  1. 云不是「远程电脑」,而是「能力的拼装」。计算、存储、网络、数据库、负载均衡、监控、编排——每个都是独立可替换的乐高块。真正的云工程师,价值在于「按需拼装」而非「单点深挖」。

  2. 能声明式就不要命令式。从安全组规则到 K8s YAML,声明终态让系统具备自愈与可复现。本文 HPA 一句话配置,抵过人工 7×24 盯盘。

  3. 成本意识要长在骨子里。弹性伸缩、按需付费不是口号——它是 HPA 把 8 副本在低谷自动缩回 2 的真实账单节省,是纯 CPU 跑中小模型而不必上 GPU 的理性取舍。

  4. 踩坑即资产。regestries.yaml 镜像加速、containerd 镜像交付、metrics-server 缺失……这些真实踩过的坑,比任何文档都记得牢。

  5. 云原生是终点也是起点。K8s + HPA 已摸到 Serverless 的门槛,而 KEDA/Knative/OpenFaaS、Service Mesh、GitOps 才是下一程。技术没有终点,只有不断把「人工运维」变成「系统自治」的过程。


小结

本篇我们用 HPA 给情感分析服务装上了「弹性引擎」:

  • 压测前:三节点 CPU 0%~1%,副本 3;
  • 压测中:CPU 冲到 188%,约 1 分钟内副本3 → 8(触顶 max),跨 3 节点承接流量;
  • 压测后:默认 5 分钟稳定窗口内自动缩回min=2

这,就是 Serverless「按需弹性、峰谷自适应」理念在 K8s 上的真实体现。HPA 是「半 Serverless」——它解决了弹性,但留着常驻副本;要彻底 scale-to-zero,请上 KEDA/Knative。

至此,从一台裸云主机,到能自愈、能伸缩、能跑 AI 的云原生集群,全栈实操闭环完成。感谢你一路同行。


配置与实测引用

  • HPA 实测:../results/16_hpa_autoscale.txt
  • AI 服务部署:../k8s/ai-service.yaml
  • AI 服务代码:../ai-service/app.py
  • 集群基础:../results/14_k8s_cluster.txt../results/15_ai_inference.txt