K8s 上 GPU 推理服务的弹性扩缩:从指标体系、控制链路到生产落地
K8s 上 GPU 推理服务的弹性扩缩:从指标体系、控制链路到生产落地
在 Kubernetes 上做 GPU 推理服务,难点从来不是“把模型跑起来”,而是如何在延迟、吞吐、成本、稳定性之间找到可持续的平衡点。
很多团队最初会把问题理解为“给 Deployment 配个 HPA 就够了”,但真正进入生产后很快会发现,GPU 推理服务的扩缩容远比 CPU Web 服务复杂:
- GPU 是昂贵且离散的资源,无法像 CPU 一样平滑超卖。
- 模型加载慢,容器启动慢,节点启动更慢,冷启动链路通常长达几十秒到数分钟。
- 单看 GPU Utilization 往往会误判负载,尤其是 LLM、Triton、vLLM 这类异步批处理推理服务。
- Pod 扩出来不代表能立刻接流量,Node 没准备好、镜像没拉完、模型没预热,都会让扩容“看起来成功,实际仍然超时”。
- 真正决定用户体验的,通常不是 GPU 使用率,而是队列长度、首 Token 延迟、P95/P99 延迟、KV Cache 水位、活跃请求数。
所以,一个成熟的方案必须从“单点扩缩工具”升级为“多层控制系统”:
- 服务层:Pod 水平扩缩容
- 资源层:GPU 节点供给与回收
- 调度层:GPU 型号、拓扑、MIG/vGPU 资源切分
- 应用层:动态批处理、并发控制、模型预热、队列保护
- 观测层:从基础 GPU 指标升级到业务 SLO 指标
这篇文章会把这条链路完整展开,给出一套适合生产环境的实现方法。
1. 先回答核心问题:GPU 推理服务到底为什么难扩缩
传统 Web 服务的扩缩逻辑大多是:
- CPU 高了,扩 Pod
- 请求少了,缩 Pod
- 节点不够了,自动加机器
但 GPU 推理不是这个范式。原因在于它更像“异构资源上的排队系统”,而不是普通无状态服务。
1.1 GPU 推理的三个本质特征
第一,资源是离散且强约束的
一个 Pod 往往直接声明:
resources: limits: nvidia.com/gpu: 1这意味着它要么拿到完整 GPU,要么根本调度不上去。和 CPU 可以按 millicore 平滑调度不同,GPU 是典型的“整卡资源”。如果节点上剩余 0.8 张 GPU,这个 Pod 仍然无法启动。
第二,单请求成本差异极大
不同请求在 token 长度、batch size、上下文长度、采样参数上差异明显。一个 128 token 的短请求和一个 8K 上下文的长请求,对显存、算力、时延的压力完全不同。
因此:
- QPS 不是唯一指标
- GPU 利用率也不是唯一指标
- “每秒请求数一样”不等于“负载一样”
第三,扩容存在显著滞后
完整扩容链路通常包括:
- HPA/KEDA 观察到指标超阈值
- Deployment 调整副本数
- 新 Pod 创建
- 调度器寻找可用 GPU 节点
- 若节点不足,Karpenter/Cluster Autoscaler 启动新节点
- 节点拉起、驱动初始化、Device Plugin 注册
- 镜像拉取
- 模型权重加载到显存
- 服务完成 warmup,readiness 成功
- Service/Ingress 开始转发流量
在生产环境里,这条路径非常常见地耗时 60 秒到 300 秒。也就是说,扩缩系统是明显滞后的控制系统,如果策略不稳,就会出现:
- 业务高峰已经过去,副本才扩出来
- 刚扩出来又缩回去,形成抖动
- 请求高峰时延暴涨,但 GPU 看起来并不高
这也是为什么 GPU 推理弹性治理必须以“预测 + 缓冲 + 稳定窗口”来设计,而不能简单照搬 CPU 服务经验。
2. 生产级目标:不要只追求“能自动扩”,要追求“扩得准、扩得稳、缩得省”
在架构设计前,建议先明确四类目标。
2.1 性能目标
- P95 延迟可控
- P99 延迟不出现雪崩
- 首 Token 时间(TTFT)在大模型场景保持稳定
- 队列等待时间不跨越业务红线
2.2 成本目标
- GPU 平均利用率尽可能高
- 低峰时自动回收节点
- 非关键流量可使用低价 Spot GPU
- 小模型、小批量任务尽可能通过 MIG/vGPU 提升密度
2.3 稳定性目标
- 扩容后新 Pod 必须在 ready 前完成模型预热
- 缩容不能中断推理中的会话或流式输出
- 单节点故障不能导致某类模型全部不可用
2.4 工程治理目标
- 扩缩逻辑标准化、可复用
- 指标可审计、阈值可解释
- 服务扩缩和节点扩缩解耦
- 平台侧能支持 Triton、vLLM、TensorRT-LLM、PyTorch 自研服务等多种推理框架
3. 推荐的总体架构:四层弹性闭环
一个成熟的 GPU 推理弹性体系,建议拆成四层。
3.1 应用层
核心职责是“承接流量并输出可用于扩缩的真实业务指标”,常见组件:
- API Gateway / Ingress
- 推理服务本体:vLLM、Triton、TensorRT-LLM、Ray Serve、自研 FastAPI/Grpc 服务
- 模型管理:权重下载、版本路由、灰度切换
- 应用指标导出器:请求队列、TTFT、tokens/s、batch size、KV Cache 使用率
3.2 指标层
由 Prometheus 统一采集两类指标:
- 基础资源指标:GPU 利用率、显存、温度、功耗、PCIe/NVLink
- 业务指标:排队长度、并发请求、TTFT、生成吞吐、错误率
3.3 控制层
负责做出扩缩决策:
- HPA:适合持续性负载、基于标准和自定义指标的扩缩
- KEDA:适合突发流量、消息堆积、队列驱动场景,也支持 scale-to-zero
- 自定义控制器:适合复杂策略,例如多指标联合判定、分模型策略、预扩容
3.4 资源层
负责供给 GPU 节点:
- Karpenter:新一代节点供给器,响应更快,实例选择更灵活
- Cluster Autoscaler:传统节点扩缩容方案
- NVIDIA GPU Operator:统一管理驱动、Toolkit、Device Plugin、DCGM Exporter
4. 扩缩决策的关键:指标体系必须从“资源指标”升级为“服务指标”
很多失败案例都不是因为没装 HPA,而是因为选错了指标。
4.1 资源指标能看机器忙不忙,但不一定能看服务是否健康
最常见的 GPU 指标包括:
DCGM_FI_DEV_GPU_UTIL:GPU 核心利用率DCGM_FI_DEV_FB_USED:显存占用DCGM_FI_DEV_MEM_COPY_UTIL:显存拷贝利用率DCGM_FI_DEV_POWER_USAGE:功耗
这些指标适合做:
- 容量评估
- 节点画像
- 资源利用率分析
- 成本审计
但它们不一定适合直接驱动扩缩容。典型问题有:
- LLM 在等待请求时 GPU Util 很低,但首包延迟已经变高
- 动态批处理生效后,GPU Util 很高,但服务依旧健康,不应该盲目扩容
- 预填充阶段显存和算力激增,解码阶段却不同,均值会掩盖真实波动
4.2 真正用于扩缩容的优先级应是业务饱和度指标
生产环境中,建议优先使用以下指标作为扩缩依据:
| 指标类别 | 推荐指标 | 作用 |
|---|---|---|
| 队列指标 | request_queue_length、waiting_requests | 直接反映积压,是扩容最敏感信号 |
| 延迟指标 | p95_latency_ms、ttft_ms | 直接映射用户体验 |
