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角色 |
|---|---|---|---|---|---|
| node1 | 113.47.6.41 | 192.168.0.252 | 8vCPU/16GiB | Ubuntu 24.04.4 | control-plane |
| node3 | 1.94.220.182 | 192.168.0.241 | 8vCPU/16GiB | Ubuntu 24.04.4 | worker |
| node4 | 124.70.102.139 | 192.168.0.150 | 8vCPU/16GiB | Ubuntu 24.04.4 | worker |
沿用前两篇集群。本篇新增依赖: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 hpa3. 施加负载
在 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;killallcurl4. 观察扩容
压测约 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 x2CPU 利用率飙升到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 模式下这部分直接省掉——对长期运行的在线服务,弹性伸缩省下的钱相当可观。
生产加固清单:
- 同时配 CPU + 内存 +(可选)QPS 多指标 HPA;
maxReplicas要卡住,防止指标异常导致无限扩容把节点打爆;- 配合PodDisruptionBudget防止缩容/驱逐时一次性干掉太多副本;
- 真正想 scale-to-zero,引入KEDA接 Kafka/HTTP/RabbitMQ 等事件源;
- 超大规模再上Cluster Autoscaler / Karpenter做节点级弹性。
11 篇实战全景回顾 + 云计算学习心得
写到这里,整个《基于华为云 FlexusX 四节点集群的云计算全栈实操》系列就完整了。回头看这 11 篇,是一条清晰的「由底向上」的云原生能力栈:
| 篇章 | 主题 | 核心收获 |
|---|---|---|
| 01~03 | 云主机 / 网络 / 安全组 | 四节点 FlexusX 基盘,VPC/安全组打通 |
| 04~05 | 块存储 / 对象存储 | EVS 持久化、OBS 非结构化存储 |
| 06~07 | 数据库 / 负载均衡 | RDS 托管库、ELB 流量入口 |
| 08 | 监控告警 | CES 指标 + 阈值告警闭环 |
| 09 | K3s 多节点 K8s 集群 | 容器编排四大能力(LB/自愈/伸缩/滚动更新) |
| 10 | 云上 AI 推理服务 | 模型容器化、containerd 镜像交付、纯 CPU 推理 |
| 11 | HPA 弹性伸缩 | Serverless 式峰谷自适应(本篇) |
几条贯穿始终的学习心得:
云不是「远程电脑」,而是「能力的拼装」。计算、存储、网络、数据库、负载均衡、监控、编排——每个都是独立可替换的乐高块。真正的云工程师,价值在于「按需拼装」而非「单点深挖」。
能声明式就不要命令式。从安全组规则到 K8s YAML,声明终态让系统具备自愈与可复现。本文 HPA 一句话配置,抵过人工 7×24 盯盘。
成本意识要长在骨子里。弹性伸缩、按需付费不是口号——它是 HPA 把 8 副本在低谷自动缩回 2 的真实账单节省,是纯 CPU 跑中小模型而不必上 GPU 的理性取舍。
踩坑即资产。regestries.yaml 镜像加速、containerd 镜像交付、metrics-server 缺失……这些真实踩过的坑,比任何文档都记得牢。
云原生是终点也是起点。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