KubeRay + vLLM:Kubernetes 上的大模型推理服务生产级部署与三级弹性伸缩实战
摘要:在大模型落地过程中,推理服务的稳定性、吞吐量和资源利用率是决定用户体验的核心指标。本文以生产环境实践为基础,详细拆解如何基于 KubeRay 与 vLLM 在 Kubernetes 集群上构建高可用的大模型推理平台,涵盖 GPU 精细化调度、三级弹性伸缩机制、PagedAttention 内存优化及全链路监控方案,力求为 AI Infra 工程师提供一套可直接落地的技术实现路径。
一、背景:推理服务的生产级痛点
随着 LLM(大语言模型)从实验室走向业务前台,推理侧的工程挑战日益尖锐。以笔者所在团队维护的 70B 参数级模型为例,上线初期我们遭遇了以下典型问题:
- GPU 显存碎片化严重:传统推理框架按请求动态分配显存,长序列请求导致 OOM(Out of Memory)频发,显存利用率长期低于 40%。
- 扩容滞后:基于 CPU 指标的 HPA 无法感知 GPU 显存压力和 Token 生成延迟,流量突增时扩容周期长达 3-5 分钟,远超用户容忍度。
- 多模型混部困难:不同业务线模型(如 7B、13B、70B)共存时,Kubernetes 默认调度器缺乏对 GPU 拓扑和 MIG(Multi-Instance GPU)的细粒度感知,导致节点负载严重不均衡。
这些问题的根源在于:Kubernetes 原生的资源调度语义与大模型推理的工作负载特征存在本质错配。vLLM 通过 PagedAttention 解决了显存管理问题,而 KubeRay 则为分布式推理提供了 Gang Scheduling 和自动扩缩容能力,两者的结合恰好补齐了生产环境的最后一块拼图。
二、整体架构:KubeRay + vLLM 的核心设计
2.1 架构全景
我们采用的架构分为四层:
- 接入层:Nginx Ingress + Redis 缓存热点 Prompt,降低重复请求对后端的压力。
- 调度层:KubeRay Operator 管理 RayCluster 生命周期,集成 KubeFlow Training Operator 处理训练与推理的混合调度。
- 推理层:vLLM 作为推理引擎,支持 Tensor Parallelism(TP)和 Pipeline Parallelism(PP),通过 Ray Serve 暴露 RESTful API。
- 存储层:S3 兼容对象存储存放模型权重,配合本地 NVMe SSD 作为二级缓存,模型加载时间从 11 分钟压缩至 20 秒。
在这套架构中,KubeRay 的核心价值在于Gang Scheduling:当 vLLM 需要以 TP=4 启动一个分布式推理实例时,KubeRay 会确保 4 个 GPU Pod 同时被调度到具备高速 NVLink 互联的同一台物理机上,避免因部分 Pod Pending 导致的资源死锁。

2.2 为什么选 KubeRay 而不是原生 Deployment?
很多团队初期会直接用 Kubernetes Deployment 部署 vLLM,但这会在生产环境埋下隐患:
| 对比维度 | 原生 Deployment | KubeRay |
|---|---|---|
| 调度语义 | 逐个调度 Pod | Gang Scheduling,全有或全无 |
| 分布式感知 | 无 | 原生支持 TP/PP 的 GPU 拓扑感知 |
| 自动扩缩容 | HPA 基于 CPU/内存 | Autoscaler 基于 Ray 任务队列深度 |
| 故障恢复 | 依赖 Pod 重启 | Ray 级 Actor 重建,状态可恢复 |
| 多租户隔离 | Namespace 级别 | Ray Queue + 资源组细粒度隔离 |
对于需要跨多卡分布式推理的 70B+ 模型,Gang Scheduling 几乎是必选项。没有它,Scheduler 可能将 Worker Pod 分散到不同节点,导致 NCCL 通信走慢速网络,TPOT(Time Per Output Token)飙升数倍。
三、生产部署实战:从 YAML 到 GPU 拓扑感知
3.1 RayCluster 资源配置
以下是我们生产环境使用的 KubeRay RayCluster 配置(已脱敏),核心要点包括:
apiVersion: ray.io/v1
kind: RayCluster
metadata:
name: vllm-70b-inference
namespace: llm-serving
spec:
rayVersion: '2.32.0'
headGroupSpec:
rayStartParams:
dashboard-host: '0.0.0.0'
block: 'true'
template:
spec:
containers:
- name: ray-head
image: vllm/vllm-openai:v0.5.4
resources:
limits:
nvidia.com/gpu: 1
memory: "64Gi"
cpu: "16"
env:
- name: VLLM_ATTENTION_BACKEND
value: "FLASH_ATTN" # FlashAttention 降低显存占用
workerGroupSpecs:
- groupName: gpu-workers
replicas: 2
minReplicas: 1
maxReplicas: 6
rayStartParams:
block: 'true'
template:
spec:
containers:
- name: ray-worker
image: vllm/vllm-openai:v0.5.4
resources:
limits:
nvidia.com/gpu: 4 # 每 Worker 4 张 A100 80G
memory: "512Gi"
cpu: "64"
env:
- name: CUDA_VISIBLE_DEVICES
value: "0,1,2,3"
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: ray.io/node-type
operator: In
values: ["head"]
topologyKey: kubernetes.io/hostname # 强制同节点部署
关键设计决策解析:
- TP=4 + PP=2 组合:70B 模型在 FP16 下约需 140GB 显存,单 Worker 4 张 A100 80G 通过 Tensor Parallelism 拆分,2 个 Worker 通过 Pipeline Parallelism 接力,实现显存与吞吐的最佳平衡。
- 强制同节点亲和性:
topologyKey: kubernetes.io/hostname确保 Head 与 Worker 落在同一物理机,避免跨节点通信瓶颈。 - FlashAttention 后端:相比传统 Attention 实现,FlashAttention-2 在序列长度 4K 时可将显存占用降低 30%,推理速度提升 1.5-2 倍。
3.2 GPU 精细化调度:MIG 与拓扑感知
在 A100/H100 集群中,我们启用了 NVIDIA Device Plugin 的 MIG 策略,使得单张物理 GPU 可被切分为多个独立实例。这对于 7B/13B 小模型混部场景至关重要:
# MIG 配置示例
spec:
containers:
- name: vllm-small
resources:
limits:
nvidia.com/mig-3g.40gb: 1 # 申请 1 个 MIG 3g.40gb 实例
同时,我们为集群部署了 NVIDIA GPU Operator 与 Node Feature Discovery(NFD),在节点上自动标注 GPU 拓扑信息:
feature.node.kubernetes.io/pci-10de.present=true
nvidia.com/gpu.product=A100-SXM4-80GB
nvidia.com/gpu.memory=81920
nvidia.com/gpu.topology.p2p=true # NVLink P2P 互联
调度时,KubeRay 的 extended resources 插件会优先选择具备 nvidia.com/gpu.topology.p2p=true 标签的节点,确保 TP 组内 GPU 通过 NVLink 高速互联。
四、三级弹性伸缩:从被动响应到主动预测
生产环境的流量特征往往是突发且不可预测的。我们设计了一套三级弹性伸缩体系,将平均扩容响应时间从分钟级压缩至秒级。
4.1 第一级:HPA 基于自定义 GPU 指标
Kubernetes 默认 HPA 只能基于 CPU/内存扩缩,无法感知 GPU 显存和 Token 延迟。我们通过 Prometheus Adapter 暴露了 vLLM 的自定义指标:
# prometheus-adapter 规则
customMetrics:
- seriesQuery: 'vllm:gpu_cache_usage_perc'
resources:
template: "<<.Resource>>"
name:
matches: "^(.*)_perc"
as: "${1}_ratio"
metricsQuery: 'avg(<<.Series>>{<<.LabelMatchers>>})'
HPA 配置如下:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: vllm-hpa
spec:
scaleTargetRef:
apiVersion: ray.io/v1
kind: RayCluster
name: vllm-70b-inference
minReplicas: 1
maxReplicas: 6
metrics:
- type: Pods
pods:
metric:
name: vllm_gpu_cache_usage_ratio
target:
type: AverageValue
averageValue: "0.75" # GPU KV Cache 利用率超 75% 触发扩容
- type: Pods
pods:
metric:
name: vllm_time_to_first_token_seconds
target:
type: AverageValue
averageValue: "800m" # TTFT > 800ms 触发扩容
4.2 第二级:KEDA 基于消息队列的事件驱动
对于异步批处理场景(如文档批量摘要),我们使用 KEDA 监听 Redis Stream 的待处理消息数:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: vllm-batch-scaler
spec:
scaleTargetRef:
name: vllm-batch-workers
triggers:
- type: redis-streams
metadata:
address: redis.llm-serving.svc:6379
stream: inference-queue
consumerGroup: vllm-consumers
pendingEntriesCount: "50" # 堆积 50 条即扩容
4.3 第三级:定时 + 预测式扩缩容
结合业务特征,我们在每日 9:00、14:00 等流量高峰前 5 分钟,通过 CronJob 预扩容:
apiVersion: batch/v1
kind: CronJob
metadata:
name: vllm-precache
spec:
schedule: "55 8,13 * * *" # 高峰前 5 分钟
jobTemplate:
spec:
template:
spec:
containers:
- name: scaler
image: bitnami/kubectl
command: ["kubectl", "scale", "raycluster", "vllm-70b-inference", "--replicas=4"]

三级伸缩的效果对比(基于生产环境 7 天数据):
| 指标 | 仅 HPA | 三级弹性体系 |
|---|---|---|
| P99 TTFT | 2.3s | 420ms |
| 平均 GPU 利用率 | 38% | 72% |
| 扩容响应时间 | 180s | 15s |
| 闲置资源成本 | 基准 | 降低 41% |
五、性能调优:PagedAttention 与请求调度策略
vLLM 的核心创新在于 PagedAttention,它借鉴操作系统虚拟内存的分页机制,将 KV Cache 划分为固定大小的块(Block),按需分配而非连续预分配。
5.1 PagedAttention 内存优化原理
传统推理框架为每个请求预分配 max_seq_len 的连续 KV Cache,导致:
- 内部碎片:实际序列长度远小于 max_seq_len;
- 外部碎片:请求完成后释放的连续空间难以复用。
PagedAttention 将 KV Cache 组织为非连续的 Block Table,每个 Block 默认 16 tokens。当序列长度从 512 增长到 4096 时,只需追加分配新 Block,无需预留连续空间。在我们的生产环境中,这一机制使单卡并发请求数从 8 提升至 32,显存利用率从 40% 提升至 85%。

5.2 请求调度策略对比
vLLM 支持多种调度策略,需根据业务场景选择:
| 策略 | 适用场景 | 特点 |
|---|---|---|
| FCFS(先到先服务) | 低延迟对话 | 简单公平,但短请求可能被长请求阻塞 |
| Shortest Job First | 多样化长度 | 最小化平均等待时间,需预估输出长度 |
| Continuous Batching | 高吞吐服务 | 动态合并新请求到正在运行的 Batch 中,吞吐量最高 |
生产环境我们采用 Continuous Batching(又称 In-flight Batching),配合 --max-num-seqs=256 和 --max-model-len=8192 参数,在延迟与吞吐之间取得平衡。
5.3 关键启动参数调优
python -m vllm.entrypoints.openai.api_server \
--model /models/Qwen2-72B-Instruct \
--tensor-parallel-size 4 \
--pipeline-parallel-size 2 \
--max-num-seqs 256 \ # 最大并发序列数
--max-model-len 8192 \ # 最大上下文长度
--gpu-memory-utilization 0.92 \ # 显存利用率上限,留 8% 缓冲
--enable-chunked-prefill \ # 大 Prefill 请求分块,降低 TTFT
--dtype bfloat16 # Ampere+ 架构推荐
其中 --enable-chunked-prefill 是 v0.5.x 引入的关键特性,它将长序列的 Prefill 阶段拆分为多个小块执行,避免单个长请求阻塞整个 Batch 的 Decode 阶段,P99 TTFT 可降低 50% 以上。
六、全链路可观测性:指标、日志与追踪
推理服务的可观测性不能仅停留在"服务是否存活",必须深入到 Token 级别的延迟分析。
6.1 核心监控指标体系
我们基于 Prometheus + Grafana 构建了四层监控大盘:
集群层:GPU 利用率、显存占用、NVLink 带宽、温度与功耗
服务层:QPS、P50/P99 TTFT、TPOT、请求成功率
引擎层:vLLM 的 gpu_cache_usage_perc、num_running_reqs、prefill_time_ms
业务层:首字返回时间、输出 Token 数、用户会话长度分布
6.2 分布式追踪
通过集成 OpenTelemetry,我们将请求从前端 Ingress 到 vLLM 的 Prefill/Decode 阶段全链路串联:
from opentelemetry import trace
tracer = trace.get_tracer("vllm.inference")
with tracer.start_as_current_span("vllm_generate") as span:
span.set_attribute("model.name", "Qwen2-72B")
span.set_attribute("input.tokens", len(input_ids))
span.set_attribute("tpot.avg_ms", avg_tpot)
# 调用 vLLM generate
在 Jaeger UI 中,可以清晰看到每个请求的 Prefill 耗时、Queue 等待耗时、Decode 逐 Token 耗时,为性能瓶颈定位提供精确依据。
七、总结与展望
本文从生产实践出发,系统性地介绍了基于 KubeRay + vLLM 构建大模型推理平台的关键技术点:
- 架构层面:利用 KubeRay 的 Gang Scheduling 解决分布式推理的 Pod 协同调度问题,利用 vLLM 的 PagedAttention 突破显存瓶颈;
- 调度层面:通过 MIG + GPU 拓扑感知实现异构模型混部,通过三级弹性伸缩应对流量波动;
- 性能层面:Continuous Batching + Chunked Prefill 显著提升吞吐,降低延迟尾部效应;
- 运维层面:构建从集群到 Token 的四层可观测体系,实现问题分钟级定位。
展望未来,随着 vLLM 对 Speculative Decoding(投机采样)和 Prefix Caching(前缀缓存)的支持日趋成熟,推理延迟有望再降低 30%-50%。而 KubeRay 与 KubeFlow、KAI Scheduler 的深度集成,也将推动训练与推理在统一集群内的无缝混部,进一步压缩 AI Infra 的总体拥有成本。
参考资料:
- vLLM 官方文档 Kubernetes 部署指南
- KubeRay 官方文档:Pipeline Parallelism 教程
- 《Performance Optimization of LLM-Based Agentic Workloads in Kubernetes Environments》TechRxiv 2025
7

被折叠的 条评论
为什么被折叠?



