【大模型基础设施工程】21:推理服务化

6 阅读29分钟

前两篇讲了 Agent 与工具调用,本质是"应用层"。再往下一层,是支撑所有 Agent / Chat / 向量检索 rerank 的推理服务层(Serving Layer)。单机跑一个 vllm serve 谁都会,但当你要同时托管 20 个模型、800 个 LoRA、每秒 2 万条请求、SLO p99 < 3s、成本要可预测,工程复杂度会陡然上升一个数量级。

这一篇把"把推理引擎做成服务"这件事拆开:服务层选型(Triton / Ray Serve / KServe / vLLM OpenAI Server ...)、多 GPU 拓扑、自动扩缩容、LoRA 多租户热加载、PD 分离部署、流量路由、K8s GPU 调度、Serverless GPU、国产云厂商的托管方案,以及灾备多活。

一、为什么"引擎"不是"服务"

1.1 从 demo 到生产的 12 个坑

python -m vllm.entrypoints.openai.api_server 跑起来,和把它变成公司级推理平台,中间差的远不只是 Dockerfile。生产化至少要回答下面这些问题:

  1. 多模型共存:Qwen3-72B、DeepSeek-V3、Qwen3-Embedding、bge-reranker-v2 要不要共享 GPU?如何调度?
  2. 多租户隔离:A 团队一次灌 10k QPS,不能打垮 B 团队的线上服务。
  3. 弹性伸缩:工作日白天 120 副本,凌晨 12 副本。扩容要几分钟?权重 140 GB 怎么拉?
  4. 流量路由:长上下文请求 ≥ 32k token 走专用池;短请求(< 2k)走共享池;带 prefix cache 的要做 session affinity。
  5. 金丝雀 / 灰度:新微调版本上线先切 1% → 5% → 100%,发现 KV cache 命中率掉了要一键回滚。
  6. 模型热切换:不停机加载/卸载 LoRA adapter、不停机切主模型版本。
  7. 可观测:每个请求的 TTFT、ITL、token/s、队列长度、GPU SM 利用率、HBM 占用、NCCL 带宽都要能查到。
  8. 灾备:一个可用区挂了,业务要能在 60s 内切到另一个可用区。权重要提前同步。
  9. 冷启动:从 Pod 调度 → 拉镜像 → 下载权重 → 加载到 HBM → warmup 首包,通常 5–15 分钟。
  10. 成本追踪:按 tenant 计 token 成本,按模型 / 按业务线分摊 GPU 账单。
  11. 协议兼容:OpenAI Chat Completions API 几乎是事实标准,Anthropic Messages、Gemini generateContent、国产厂商自有 API 都要能接。
  12. 合规与安全:输入 PII 脱敏、输出内容审核、审计日志保留期。

前面 111213 篇关心的是"单 GPU 把 token 吐得多快";这一篇关心的是"一整个集群能不能稳定、便宜、可维护地吐 token"。

1.2 分层视图

┌───────────────────────────── Client / Agent ─────────────────────────────┐
│    OpenAI SDK · Anthropic SDK · LangChain · 业务微服务                   │
└──────────────────────────────────┬──────────────────────────────────────┘
                                   ▼
┌──────────────────── LLM Gateway(下一篇 22)────────────────────────────┐
│  多租户鉴权 · 限流配额 · 路由 · 审计 · 内容审核 · 成本统计               │
└──────────────────────────────────┬──────────────────────────────────────┘
                                   ▼
┌──────────────────── 推理服务层(本篇)──────────────────────────────────┐
│  KServe / Ray Serve / Triton / BentoML / K8s Deployment                │
│  自动扩缩 · 模型仓库 · PD 分离 · LoRA 多租户 · Session Affinity         │
└──────────────────────────────────┬──────────────────────────────────────┘
                                   ▼
┌──────────────────── 推理引擎(第 13 篇)────────────────────────────────┐
│  vLLM · SGLang · TensorRT-LLM · TGI · MindIE · XServe                  │
└──────────────────────────────────┬──────────────────────────────────────┘
                                   ▼
┌─────────────────── 硬件底座(第 24 篇)────────────────────────────────┐
│  GPU · NVLink · IB/RoCE · 昇腾 / 寒武纪 / 燧原                         │
└─────────────────────────────────────────────────────────────────────────┘

网关(Gateway)和服务层(Serving)经常被混在一起,其实职责不同:网关关心"谁"和"多少"(身份、配额、合规),服务层关心"在哪"和"怎么跑"(拓扑、实例、KV cache、GPU)。很多团队早期放在一个进程里,规模上来一定会拆。

1.3 一次真实事故的复盘

为了让上面 12 个问题具象化,这里复盘一次 2024 年末我们团队亲历的事故(细节脱敏):

  • 背景:单一 vLLM 集群、32 副本 Qwen2.5-72B、TP=4、H100,KV cache 占用 65 GB/副本。
  • 触发:业务方上线了一个"长文档问答"功能,平均 prompt 12k token,未上线前平均 800 token。
  • 现象:p99 TTFT 从 1.8s 涨到 28s,GPU 利用率反而从 75% 掉到 40%,队列长度暴涨。
  • 根因
    1. 没做长短分流。长请求把 prefill 填满,短请求被饿。
    2. 没有 Session affinity,长对话每轮都重算 12k prefix。
    3. 没开 --enable-prefix-caching,历史 KV 无法复用。
    4. 扩容基于 CPU 利用率,GPU 爆了但 HPA 没触发。
  • 紧急修复:打开 prefix caching、切到 KEDA + num_requests_waiting 扩容、在网关层按 input 长度拆到两个池。
  • 长期:上线 LMCache 跨副本 KV 复用;后续在高端客户上线 PD 分离。

教训:推理服务的稳定性,80% 来自路由和拓扑的正确性,20% 才是引擎参数

二、服务层工具选型

2.1 Nvidia Triton Inference Server

Triton 是老牌推理服务框架,设计目标是"模型无关",支持 TensorRT、TensorRT-LLM、vLLM、PyTorch、ONNX、Python、FIL 等多个 backend。它的几个杀手级特性:

  • Dynamic Batching:非 LLM 模型可按 latency 窗口自动 batch。
  • Ensemble / Business Logic Scripting(BLS):在 Triton 里用 Python backend 组合多个模型(ASR → LLM → TTS)。
  • Model Repository:基于目录结构的模型版本管理,支持 poll 模式热加载。
  • gRPC / HTTP / metrics:自带 Prometheus 指标、可对接 DCGM。

LLM 场景下,Triton 主要作为 TensorRT-LLM 的官方 servertensorrtllm_backend)使用,适合 Nvidia 全家桶用户。缺点是配置文件(config.pbtxt)偏繁琐、Python 生态不如 Ray Serve 灵活。

目录结构示例:

model_repository/
├── qwen3-72b/
│   ├── config.pbtxt
│   └── 1/
│       └── model.plan       # TRT-LLM engine
└── ensemble_rag/
    ├── config.pbtxt
    └── 1/
        └── model.py         # BLS 脚本

2.2 Ray Serve

Ray Serve 是 Anyscale 出品的 Python-first 服务框架,和 Ray(任务 / 集群)深度集成。适合:

  • 异构模型组合:一个 deployment graph 同时挂 LLM、embedding、reranker、CV、音频。
  • 有状态 actor:每个副本就是一个 Ray actor,天然适合 vLLM engine 这种需要常驻显存的服务。
  • DAG / Fan-out:RAG pipeline 天然可以写成 @serve.deployment + ingress.bind(rag_chain)
  • 自动扩缩:基于 replica 级别的 RPS、队列长度。

缺点:对 K8s 原生语义不够好(Ray 自带集群管理),跨语言支持弱,对 SRE 团队"Ray 集群"本身是新的运维对象。

2.3 KServe(K8s CRD 标准)

KServe 脱胎于 KubeFlow 的 KFServing,目标是在 K8s 上用标准 CRD 描述推理服务。核心资源:

  • InferenceService:最顶层资源,描述一个服务(transformer + predictor + explainer)。
  • ServingRuntime / ClusterServingRuntime:引擎运行时模板(vLLM、Triton、Hugging Face TGI、TorchServe 等)。
  • 集成 Knative Serving(scale-to-zero)、Istio(流量切分)、Cert-Manager(TLS)。

KServe 的定位类似"K8s 原生的 SageMaker Endpoint"。对大部分想在 K8s 上跑推理又不想自己写 Operator 的团队,是默认选择。下文有 YAML 示例。

2.4 Seldon Core

Seldon Core 是 KServe 的"兄弟项目"(历史更早),也是 K8s CRD。v2 版本叫 Seldon Core v2,架构更偏流水线和多模型编排(model mesh),适合大量小模型的场景——比如几千个推荐模型。LLM 场景用得少。

2.5 TorchServe

PyTorch 官方的模型服务器。API 简单、对 Torch 生态友好,但 LLM 专用优化(连续批处理、Paged Attention)需要自己造或走 PyTorch / Meta 系的发行版(TorchServe + vLLM)。国内 LLM 场景很少单独用 TorchServe。

2.6 BentoML / Yatai / OpenLLM

BentoML 强调"Python 开发者友好":用装饰器把推理函数包成 Servicebentoml build 打成 OCI 镜像,bentoml deploy 到 K8s(Yatai)或 BentoCloud。对初创团队、算法同学自助上线小型服务非常友好。OpenLLM 是他们针对 LLM 的子项目,支持 vLLM / TensorRT-LLM。

2.7 vLLM / SGLang 自带 OpenAI Server

这是 2024–2025 年的事实默认:直接起一个 python -m vllm.entrypoints.openai.api_server --model ...,加一个 nginx / Envoy 前面当负载均衡,就是一个"够用"的生产服务。SGLang 的 python -m sglang.launch_server 类似。

什么时候它不够用?

  • 需要跨模型 / 跨引擎路由(vLLM + TRT-LLM 混合)。
  • 需要深度定制调度(如按 tenant 隔离 KV block pool)。
  • 需要 PD 分离、动态 LoRA 切换、模型热升级。

满足这些时就要上 KServe / Ray Serve 之类。

2.8 选型决策表

场景推荐
单模型、快速上线、OpenAI 协议vLLM / SGLang 自带 server + Envoy
K8s 原生、标准化、需要 GitOpsKServe + vLLM ServingRuntime
Python 复杂 DAG、多模型组合Ray Serve
Nvidia 全家桶、TRT-LLM 重度用户Triton + tensorrtllm_backend
算法同学自助打包BentoML / OpenLLM
托管省心云厂商(PAI-EAS / 火山 / Bedrock / Vertex)

三、多 GPU 拓扑

第 6 篇讲了训练并行策略,推理这边简单一些,但同样重要。

3.1 单机多卡:TP 为主

单节点 8×H100 SXM(NVLink 900 GB/s 互联),跑 72B、110B 模型的首选是 Tensor Parallel(TP)。vLLM 里就是 --tensor-parallel-size 8。TP 的通信模式是 all-reduce / all-gather,对 NVLink 友好,跨节点会显著掉性能(IB 200 Gbps ≈ 25 GB/s,比 NVLink 慢一个数量级)。

经验公式:

  • 70B fp16 ≈ 140 GB 权重 + KV cache,至少 2×H100-80G(TP=2)。
  • 405B fp16 ≈ 810 GB,单机 8×H100-80G 装不下,必须跨机。
  • FP8 / INT4 量化后(见 14 篇)可大幅压缩,72B 能单卡 H100 跑起来。

3.2 多机:TP × PP

跨节点时:

  • TP 留在机内(NVLink / NVSwitch 域)。
  • PP(流水线并行)跨机,用 IB / RoCE。PP 通信量小(只有 stage 边界的激活),对带宽不敏感。
  • EP(专家并行) 用于 MoE 模型(DeepSeek V3 / Qwen3-MoE),把 expert 切到不同节点。

典型拓扑:DeepSeek V3 671B 推理,单副本跨 2 机 16 卡 H20,TP=8, PP=2, EP=16

3.3 副本(DP)扩展

同一个模型配置,多个独立副本,前面挂负载均衡——这是"水平扩容"。副本数由 QPS 决定,不由模型大小决定。

           ┌── Replica 1 (8×H100, TP=8) ──┐
 LB ──┬────┼── Replica 2 (8×H100, TP=8) ──┤──► Clients
      │    └── Replica 3 (8×H100, TP=8) ──┘

3.4 拓扑感知调度

K8s 默认调度器对 GPU 拓扑无感知。你需要:

  • Nvidia device plugin:把 GPU 当成资源 nvidia.com/gpu
  • NVIDIA GPU Operator:一键部署 device plugin + DCGM + MIG 管理。
  • Topology Manager:Kubelet 的特性,尽量把同一个 Pod 的 GPU / CPU / NUMA 放一起。
  • 拓扑感知调度器:Volcano、Koordinator、kai-scheduler,理解"这 8 张卡必须在同一个 NVSwitch 域"。

四、自动扩缩容

4.1 指标驱动:KEDA

HPA 默认只能基于 CPU / Memory,不够。KEDA(Kubernetes Event-Driven Autoscaler) 支持 40+ 种 scaler:Prometheus、Kafka、Redis、SQS 等。LLM 场景常用:

  • Queue length scaler(通过 Prometheus):vllm_num_waiting_requests > 阈值就扩容。
  • GPU utilization scaler:DCGM 采集 DCGM_FI_DEV_GPU_UTIL
  • 自定义指标:P99 TTFT > 3s、prefill batch 占满时长。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: vllm-qwen3-scaler
spec:
  scaleTargetRef:
    name: vllm-qwen3
  minReplicaCount: 2
  maxReplicaCount: 32
  pollingInterval: 15
  cooldownPeriod: 120
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus.monitoring:9090
      query: |
        avg(vllm:num_requests_waiting{service="qwen3"})
      threshold: "8"

4.2 Knative Serving:scale-to-zero

Knative Serving 能把无流量的模型缩到 0 副本——但 LLM 推理场景慎用。模型权重几十到几百 GB,冷启动 5–15 分钟,用户第一个请求就超时了。Knative 适合:

  • 小模型(< 10 GB)、长尾使用。
  • 内部批处理任务,延迟不敏感。
  • 配合"预热副本"策略(min-scale=1)的非主力模型。

4.3 冷启动优化

这是 LLM serving 最大的工程痛点之一。一个权重 140 GB 的 Qwen3-72B,冷启动时间分解:

总冷启动 ≈ 10 分钟
├── Pod 调度 + 镜像拉取        ~60s    → 镜像加速
├── 权重下载(S3 → 本地 NVMe) ~180s   → 本地缓存 / pre-pull
├── 权重 mmap 到 HBM           ~120s   → fast loader
├── CUDA graph 构建            ~60s    → 持久化
├── warmup(生成几条假请求)   ~30s    → 保留

优化手段:

  • PVC / hostPath 缓存:每个节点的 NVMe 上缓存权重,相同模型不再重复下载。
  • 镜像加速:Dragonfly、P2P 分发;阿里云用 ACR 镜像加速;AWS 用 SOCI。
  • CSI snapshot:权重做成只读卷快照,新副本秒级挂载。
  • Pre-pull DaemonSet:节点一上线就后台拉权重,不等 Pod 调度。
  • Safetensors 多线程加载 / torch.load(mmap=True):加载阶段 3–5 倍加速。
  • CUDA graph 缓存:vLLM 的 --enforce-eager=False 首次构建慢,可落盘复用。
  • Over-provision:keep N+1 副本 warm,哪怕有 5% 冗余也值。

五、模型热加载与多租户 LoRA

5.1 为什么 LoRA 多租户重要

第 19、20 篇讨论了业务层面经常需要"一个基座模型 + 几十到几千个小微调"的模式:某客服场景、某风控场景、某领域术语各一份 LoRA(几十 MB 到几百 MB)。如果为每个 LoRA 起一副 72B 副本,成本爆炸。

解决方案:共享基座 + 动态加载 LoRA adapter

5.2 S-LoRA / Punica / vLLM LoRA

  • S-LoRA(UCB 2023):首次提出把多个 LoRA adapter 同时 serve 的系统方案,支持数千个 adapter 并发,核心是统一的内存管理和 batched gather。
  • Punica(CMU 2023):SGMV(Segment Gather Matrix-Vector)kernel,让不同 adapter 的 batch 能一把算完。
  • vLLM LoRA Adapter(生产默认):--enable-lora --max-loras 16 --max-lora-rank 64,请求头带 model: qwen3-lora-finance,vLLM 查表命中对应 adapter。Adapter 可以在 S3 / OSS 上,动态拉下来。
python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen3-32B \
  --enable-lora \
  --max-loras 32 \
  --max-lora-rank 64 \
  --lora-modules \
    finance=s3://bucket/loras/finance-v3 \
    legal=s3://bucket/loras/legal-v2

5.3 LMCache:跨请求 KV 复用

LMCache 把 KV cache 外置到 CPU 内存 / NVMe / 对象存储,让相同 prefix 在不同副本间也能复用。典型用途:

  • RAG:几十份文档反复命中 → prefix 固定 → 把 KV 存下来。
  • System prompt 很长的 agent:每次 reload KV 比 recompute 快 5–20 倍。
  • 会话级缓存:用户同一 session 第二轮请求直接复用上一轮 KV。

vLLM v0.6+ 已原生集成 --kv-transfer-config

六、PD 分离部署(Prefill-Decode Disaggregation)

6.1 为什么要分离

LLM 推理两阶段差异极大:

阶段计算特征瓶颈批处理
Prefill一次 prompt、大矩阵乘算力 bound喜欢大 batch
Decode每次一个 token、KV 查表访存 bound喜欢小步快

同一个 GPU 上混跑,prefill 的尖峰会抢占 decode 的带宽,造成 ITL(inter-token latency)抖动。经典连续批处理用 "chunked prefill" 缓解(见 12 篇),但没根治。

PD 分离 的思路:把 prefill 和 decode 放到不同 GPU 池,prefill 完成后把 KV cache 通过高速网络传给 decode 节点。

6.2 主流方案

  • Mooncake(Kimi / 月之暗面):首个生产级 PD 分离系统,KV 存到 CPU 内存池("KVCache Store"),RDMA / GDS 高速传输,核心创新是 KV-centric 调度(按 KV 亲和性而非请求亲和性分配)。2024 年开源后成为标准参考。
  • DistServe(UCSD 2024):最早系统研究 PD 分离的论文,论证在相同 SLO 下吞吐提升 4–8 倍。
  • Splitwise(Microsoft):Azure 上的工程落地,同时做节能(prefill 用高算力卡,decode 用高带宽卡)。
  • DeepSeek V3 的 PD + MoE 分离:不仅 PD 分离,MoE expert 也分离到专用 EP 节点,prefill 节点、decode 节点、expert 节点三层。
  • vLLM v1:原生支持 --kv-transfer-config,可配合 NIXL、Mooncake Store、LMCache 做 KV 传输。

6.3 PD 分离架构 SVG

PD 分离架构 SVG转存失败,建议直接上传图片文件

6.4 何时上 PD 分离

不要过早上。判据:

  • Prefill / Decode 算力与带宽需求差异大(长 prompt、短输出的场景,如文档 QA)。
  • SLO 对 TTFT 和 ITL 都敏感,chunked prefill 已经调不动。
  • 集群 ≥ 数十节点,运维能承担额外复杂度(KV 存储、网络拓扑、调度器)。

小规模集群,老老实实用 vLLM + chunked prefill 就够了。

6.5 PD 比例与异构搭配

PD 分离不是"各 50%"。实测中,比例与负载高度相关:

业务形态平均输入平均输出典型 P:D 比
短 Chat5003001 : 3
文档 QA12k5003 : 1
代码补全6k2004 : 1
Agent 多轮8k(含历史)1k2 : 1

工程上,Prefill 池用算力强的卡(H100 SXM)、Decode 池用带宽强成本低的卡(H20 / L20 / MI300X) 能得到最优的 TCO。DeepSeek V3 推理就是这个配方。

6.6 KV 传输介质

KV 从 Prefill 到 Decode,要跨节点搬数据。几种典型通道:

  • RDMA (IB/RoCE):最主流,GPUDirect RDMA(GDR)能让 KV 直接从一个 GPU HBM 搬到另一个,经过 CPU bounce 的开销最低。
  • NVLink-Network / NVSwitch:同机柜 NVLink Fabric 下,KV 搬运近乎零开销,但受限于机柜物理域。
  • NIXL(NVIDIA Inference Xfer Library):统一抽象 RDMA / NVLink / GDS,vLLM v1、Dynamo 都已集成。
  • 共享 CPU 内存 + DPDK:成本更低但延迟较高,适合 batch 场景。

七、流量路由

7.1 Session affinity(prefix cache 友好)

前面讲了 KV cache 复用:同一用户同一会话的多轮对话要尽量命中同一副本,否则 prefix cache 失效,每轮都要重算 system prompt + 历史。

做法:

  • 一致性哈希(consistent hashing):hash(session_id) mod N
  • Envoy/Istio 的 hash_policy: header: x-session-id
  • 自定义路由:按 prompt prefix 指纹路由,用 bloom filter 或 learned router 判断"哪个副本最可能已有这段 KV"。vLLM 的 Sticky Routing extension、SGLang Router 都在做这方面。

7.2 长短请求分流

混部长请求(输入 32k+、输出 4k+)和短请求(输入 500、输出 100)会严重拖慢短请求的 p99。分流策略:

  • 两池子:长请求池(大 max_model_len、大 KV cache)vs 短请求池(高并发、小 KV)。
  • 按 input token 数路由:网关层估算 token 数(tiktoken / BPE),> 8k 走长池。
  • SLO 感知:给每类流量定不同 SLO,动态调权重。

7.3 成本 / 延迟 SLO 路由

多模型场景下,可以做 model cascade

  1. 先走 4B 小模型。
  2. 置信度低 / 用户明确选了 "deep mode" 再走 72B。
  3. 最终兜底走顶级模型(DeepSeek-V3、GPT-5)。

这本质是网关层的事(下一篇讲),但服务层要提供不同模型的同构 API 和一致的 metric 口径。

八、模型仓库

权重从哪里来?

  • HuggingFace Hub:全球事实标准,支持 huggingface-cli download、LFS、safetensors。
  • ModelScope(魔搭):阿里牵头的国内镜像 + 原生发布源。Qwen、GLM、百川、面壁等国产模型基本都双发 HF + MS。国内访问 HF 困难时优先用 MS。
  • 企业私仓
    • S3 / OSS / COS:最常见,版本以 prefix 区分(s3://models/qwen3-72b/v1.2.0/)。
    • HuggingFace 私有模型:付费企业版支持 SSO + 私仓。
    • OCI Artifact:Distribution spec 也能装模型(ORAS 工具),好处是和镜像仓库共用基础设施。
  • Harbor / ACR:把模型做成 OCI 制品,与 K8s / ArgoCD 集成最平滑。

最佳实践:私仓 + 哈希校验 + 不可变版本。不要依赖"latest",上游偶尔会覆盖。

九、K8s 上的 GPU

9.1 GPU 接入

  • nvidia-device-plugin:把 /dev/nvidia* 和 GPU 当成 K8s 可调度资源。
  • GPU Operator:一键部署 device plugin、DCGM、MIG Manager、node feature discovery。
  • 资源请求resources.limits.nvidia.com/gpu: 8

9.2 MIG(Multi-Instance GPU)

A100 / H100 支持把一张卡切成 7 份(1g.10gb、2g.20gb、3g.40gb、7g.80gb)。适合:

  • 嵌入模型、小 reranker、安全分类器——用不到整卡。
  • 多租户硬隔离(MIG 的 HBM 和 SM 都是物理隔离)。

不适合:LLM 推理(fragmentation,MIG 之间不能 NVLink)。

9.3 拓扑感知调度

  • Topology Manager:kubelet 级别,确保同一个 Pod 的 GPU/NIC/CPU 在一个 NUMA。
  • Volcano:批处理调度器,支持 gang scheduling(多卡同时起,要么都起要么都不起),LLM 多卡副本必备。
  • Koordinator / kai-scheduler:更懂 NVLink / NVSwitch 拓扑。
  • Kueue:K8s 原生作业队列,可做 tenant 级 quota。

9.4 网络

  • RDMA 共享rdma/hca resource + SR-IOV,让 Pod 能用 IB。
  • HostNetwork:省 CNI 开销,但失去网络策略,慎用。
  • Multus:给 Pod 加第二张网卡走 RDMA。

9.5 KubeFlow / Volcano / Arena

  • KubeFlow:端到端 ML 平台,Pipelines / Training Operator / Notebook。
  • Volcano:批处理 + gang scheduling,训练 / 推理都常用。
  • Arena(阿里):KubeFlow 的 CLI 封装,国内用户友好。

十、Serverless GPU

10.1 商业方案

  • Modal:DX 最好的 Serverless GPU 平台,Python 装饰器 @app.function(gpu="A100") 直接上线。冷启动秒级(靠镜像快照 + 权重 FS 层)。
  • RunPod:按秒计费的 GPU serverless,A100/H100 在售,适合批处理。
  • Replicate:主打开源模型一键 API,按 token/秒双计价,偏 2C。
  • Fly Machines:全球 PoP 部署,启动快(Firecracker VM),适合小模型。
  • AWS Lambda GPU / SageMaker Serverless Inference:AWS 体系内的 serverless,支持小模型。Bedrock 本身也是 serverless 调用。
  • Azure Container Apps(GPU)/ GCP Cloud Run(GPU):两家都在 2024–2025 推出了 Serverless GPU。

10.2 适用场景

  • 尖峰流量:营销活动、大 V 发帖后的几分钟。
  • 长尾模型:调用量低但必须存在。
  • 批处理 / 离线任务:embedding、OCR、图文标注。

不适用:核心在线主链路(冷启动风险)、超大模型(权重分发成本)。

十一、国产云厂商托管推理服务

11.1 阿里云 PAI-EAS(Elastic Algorithm Service)

阿里 PAI 平台的推理服务产品。特点:

  • 一键部署 HuggingFace 模型、Qwen 系列 model card。
  • 支持 blade / TensorRT-LLM / vLLM 多 backend。
  • 深度集成 OSS(模型仓库)、ACK(K8s)、SLB(负载均衡)、ARMS(观测)。
  • 灰度发布、金丝雀、蓝绿开箱即用。

11.2 火山引擎 veMLP / 方舟

字节旗下,方舟(Ark)对外主要是大模型 API(豆包、DeepSeek 托管),veMLP 则是底层 ML 平台。火山在 RDMA 网络 / 高性能对象存储(TOS)方面投入很大,PD 分离、KV 外存等特性上线较早。

11.3 腾讯云 TI-ACC / TI-ONE

TI-ONE 是腾讯的 ML 平台,TI-ACC 是推理加速产品,支持混元系列和开源模型。与 TDMQ / COS / TKE 集成。

11.4 华为 MindIE Service

华为 CANN 生态的上层服务框架,把 MindIE 引擎(第 13 篇提到)包成 OpenAI 兼容 API,部署在昇腾 910B/910C 集群上。盘古、通义千问昇腾版、DeepSeek 昇腾版均走这个栈。昇腾集群上的事实标准。

11.5 字节 XServe(内部)

字节内部大模型推理服务平台,外部可以通过火山方舟看到它的能力外溢。强调端到端全链路优化、PD 分离、超大规模多租户。

11.6 国际对照

  • AWS Bedrock:Serverless,Claude、Llama、Titan 等;企业要私有化见 SageMaker JumpStart。
  • Azure OpenAI / AI Foundry:GPT、o 系列、Llama、Mistral。
  • GCP Vertex AI:Gemini、Anthropic、Llama;Model Garden 支持一键部署。
  • Databricks Mosaic AI Model Serving:主打企业定制 + 评估闭环。

十二、灾备与多活

LLM 推理的 DR(Disaster Recovery)有两大难点:权重大 + GPU 稀缺

12.1 跨 region 副本

  • 主 region 挂 N 副本,备 region 挂 ⌈N/3⌉ warm 副本(日常承载 10–30% 流量)。
  • 切流通过上层网关 / DNS(weighted routing)。
  • 权重要提前同步。典型做法:OSS/S3 跨区复制 + 节点本地缓存 + pre-pull DaemonSet。

12.2 降级模型

当主模型(例如 405B)某 region 完全不可用:

  1. 切到同 region 的 降级模型(70B、32B 的 Qwen3、Llama 同能力档)。
  2. 或切到 备 region 主模型(可能延迟增加 50–150 ms)。
  3. 最差情况走 外部 API(Bedrock / 方舟),成本提高但保可用。

这需要网关层能做:SLA 检测 → 自动切流 → 回切,且对客户端保持 API 兼容。

12.3 故障演练

  • Chaos Engineering:定期 kill Pod、模拟 GPU ECC 错误、断开 IB 链路。
  • 引擎级:kill 一个 TP rank 看 vLLM 能否 graceful restart。
  • KV 存储:断开 RDMA 看是否 fallback 到 recompute。

十三、代码示例

13.1 KServe + vLLM

KServe 官方有 vllm-openai ServingRuntime 模板。先定义运行时:

apiVersion: serving.kserve.io/v1alpha1
kind: ClusterServingRuntime
metadata:
  name: kserve-vllm-runtime
spec:
  annotations:
    prometheus.kserve.io/path: /metrics
    prometheus.kserve.io/port: "8080"
  supportedModelFormats:
  - name: huggingface
    version: "1"
    autoSelect: true
  protocolVersions: [v2]
  containers:
  - name: kserve-container
    image: vllm/vllm-openai:v0.9.0
    args:
    - --model=/mnt/models
    - --port=8080
    - --served-model-name={{.Name}}
    - --tensor-parallel-size=2
    - --max-model-len=32768
    - --enable-prefix-caching
    resources:
      limits:
        nvidia.com/gpu: "2"
        memory: 64Gi
      requests:
        nvidia.com/gpu: "2"
        memory: 32Gi
    ports:
    - containerPort: 8080
      protocol: TCP

再定义 InferenceService:

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: qwen3-32b
  annotations:
    serving.kserve.io/autoscalerClass: keda
spec:
  predictor:
    minReplicas: 2
    maxReplicas: 16
    model:
      modelFormat:
        name: huggingface
      runtime: kserve-vllm-runtime
      storageUri: s3://my-bucket/models/qwen3-32b/
      resources:
        limits:
          nvidia.com/gpu: "2"
    nodeSelector:
      nvidia.com/gpu.product: NVIDIA-H100-80GB-HBM3

验证:

kubectl apply -f qwen3-32b.yaml
kubectl get isvc qwen3-32b
# 等待 READY=True 后:
ENDPOINT=$(kubectl get isvc qwen3-32b -o jsonpath='{.status.url}')
curl -H 'Content-Type: application/json' \
  -d '{"model":"qwen3-32b","messages":[{"role":"user","content":"hello"}]}' \
  $ENDPOINT/v1/chat/completions

13.2 Ray Serve 多模型 Composition

一个同时挂 Qwen3(主 LLM)、bge-m3(embedding)和一个路由器的 deployment:

import ray
from ray import serve
from fastapi import FastAPI
from pydantic import BaseModel
from vllm import LLM, SamplingParams
from sentence_transformers import SentenceTransformer

app = FastAPI()


class Query(BaseModel):
    text: str
    mode: str = "auto"  # auto | llm | embed


@serve.deployment(
    ray_actor_options={"num_gpus": 2},
    autoscaling_config={"min_replicas": 1, "max_replicas": 8, "target_ongoing_requests": 4},
)
class Qwen3LLM:
    def __init__(self):
        self.llm = LLM(model="Qwen/Qwen3-8B", tensor_parallel_size=2, gpu_memory_utilization=0.9)
        self.params = SamplingParams(max_tokens=512, temperature=0.2)

    async def __call__(self, prompt: str) -> str:
        outs = self.llm.generate([prompt], self.params)
        return outs[0].outputs[0].text


@serve.deployment(ray_actor_options={"num_gpus": 0.5})
class BgeEmbedding:
    def __init__(self):
        self.model = SentenceTransformer("BAAI/bge-m3", device="cuda")

    async def __call__(self, text: str):
        return self.model.encode(text, normalize_embeddings=True).tolist()


@serve.deployment
@serve.ingress(app)
class Router:
    def __init__(self, llm, embed):
        self.llm = llm
        self.embed = embed

    @app.post("/infer")
    async def infer(self, q: Query):
        if q.mode == "embed" or (q.mode == "auto" and len(q.text) < 64):
            vec = await self.embed.remote(q.text)
            return {"type": "embedding", "vector": vec[:8], "dim": len(vec)}
        text = await self.llm.remote(q.text)
        return {"type": "text", "answer": text}


llm_handle = Qwen3LLM.bind()
embed_handle = BgeEmbedding.bind()
app_handle = Router.bind(llm_handle, embed_handle)

# ray start --head
# serve run serving:app_handle

启动:

ray start --head --num-gpus=3
serve run serving:app_handle
curl -X POST http://localhost:8000/infer -H 'Content-Type: application/json' \
  -d '{"text":"解释一下 KV cache","mode":"auto"}'

关键点:LLM 是 num_gpus=2(TP=2),embedding 用 num_gpus=0.5(共享半张卡),Ray Serve 自动帮你把两者放到合适的节点,Router 负责路由。

13.3 vLLM 启动带 LoRA 多租户 + KV 外存

python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen3-32B \
  --tensor-parallel-size 2 \
  --enable-prefix-caching \
  --enable-lora --max-loras 32 --max-lora-rank 64 \
  --lora-modules finance=/models/loras/finance legal=/models/loras/legal \
  --kv-transfer-config '{"kv_connector":"LMCacheConnector","kv_role":"kv_both"}' \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.9

13.4 SGLang Router:prefix-aware 路由

SGLang 提供的 Router 组件可以做 cache-aware routing,按 prompt prefix 命中哪个副本有 KV 来分发:

# 启动 3 个 SGLang worker
for port in 30000 30001 30002; do
  python -m sglang.launch_server --model Qwen/Qwen3-8B --port $port &
done

# 启动 Router(同机或独立)
python -m sglang_router.launch_router \
  --worker-urls http://localhost:30000 http://localhost:30001 http://localhost:30002 \
  --policy cache_aware \
  --cache-threshold 0.5 \
  --balance-abs-threshold 32 \
  --port 8000

# 请求打到 8000,Router 决定具体发哪个 worker
curl -X POST http://localhost:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"qwen3","messages":[{"role":"user","content":"hello"}]}'

相比一致性哈希,cache_aware 在 RAG / agent 场景命中率能高出 15–40 个百分点。

13.5 基准测试

上线前必做容量评估。推荐工具链:

  • vllm bench serve / benchmark_serving.py:官方脚本,支持 ShareGPT、LongBench、合成 trace。
  • genai-perf(NVIDIA):Triton 体系的标准压测工具,也能压任何 OpenAI 兼容 API。
  • llmperf(Anyscale 维护):多 tenant / 多并发场景的方便封装。
  • k6 + OpenAI plugin:写自定义业务 trace 的首选。

关键指标至少采集:TTFT p50/p99、ITL(每 token 间隔)p50/p99、吞吐(tokens/s)、GPU 利用率、HBM 利用率、prefix cache 命中率、排队时长。

python benchmarks/benchmark_serving.py \
  --backend vllm \
  --model Qwen/Qwen3-32B \
  --dataset-name sharegpt \
  --dataset-path ShareGPT_V3.json \
  --num-prompts 2000 \
  --request-rate 40 \
  --host localhost --port 8000 \
  --save-result --result-filename qwen3-32b.json

输出的 p99 TTFTp99 TPOT(time per output token)、mean_throughput 就是你给 SRE / 业务方承诺 SLO 的依据。

十四、整体架构 SVG

整体架构 SVG转存失败,建议直接上传图片文件

十五、GPU 共享与小模型共存

LLM serving 不都是 72B 巨兽。一个典型平台还要跑:embedding(300M–2B)、rerank(500M)、safety classifier(100M)、ASR/TTS。如果每个都独占一张卡,钱包会爆。

15.1 MPS(Multi-Process Service)

Nvidia MPS 允许多个进程共享一块 GPU 的 SM,比默认的时分复用(context switch)开销更低。K8s 里通过 nvidia.com/gpu.shared = true 或 HAMi / TimeSlicing Plugin 接入。适合:

  • 低并发的 embedding 服务。
  • Batch 评估任务。
  • 共享开发环境。

不适合:高 QPS LLM 主推理(干扰严重,p99 抖动大)。

15.2 MIG vs Time-Slicing vs MPS

特性MIGTime-SlicingMPS
隔离硬件级 HBM / SM无(时分)SM 共享,显存共享
卡支持A100/H100所有所有
性能干扰有(低)
适合多租户、小模型开发环境低并发推理

15.3 HAMi / vGPU

国内常用 HAMi(由第四范式等维护,原 4paradigm/k8s-vgpu-scheduler),可以把一张卡按 显存 + 算力百分比 切给多个 Pod。它是 MPS 之上的调度层,对昇腾、寒武纪也有适配。

十六、上线前 checklist

  • 选定 serving 框架(KServe / Ray Serve / vLLM OpenAI / Triton / 托管)。
  • 选定引擎(vLLM / SGLang / TRT-LLM / MindIE)及版本锁定策略。
  • 模型仓库方案(HF / MS / 私有 S3 / OCI)+ 哈希校验。
  • GPU 资源池(H100 / H20 / 910B)规划,算准 TP/PP 拓扑。
  • 冷启动预案(pre-pull / CSI snapshot / warm 副本)。
  • 自动扩缩策略(KEDA + 业务指标,非 CPU/Mem)。
  • Session affinity(prefix cache 友好)+ 长短分流。
  • LoRA 多租户是否开启、adapter 数量上限。
  • PD 分离是否上线(规模 < 20 节点大概率不需要)。
  • KV cache 外存(LMCache / Mooncake)是否上线。
  • 可观测栈:Prometheus + DCGM + TTFT/ITL/p99 看板。
  • 金丝雀 + 回滚流程。
  • 跨 region 灾备 + 降级模型路径。
  • 成本按 tenant / 按模型分摊。
  • 安全:mTLS、模型权重加密、输入输出审计留存。

十七、常见问答(FAQ)

Q1:我刚起步,只有 2–4 张 GPU,还需要上 KServe / Ray Serve 吗?

不需要。直接 vllm serve + systemd / Docker Compose + 前面一个 nginx 足够撑很久。等团队有 ≥ 10 副本、需要 GitOps、多租户、金丝雀时再迁移。

Q2:Ray Serve 和 KServe 如何选?

  • 算法驱动、Python 复杂 DAG、已有 Ray 训练集群 → Ray Serve。
  • SRE 驱动、K8s 原生、已有 Istio/Prometheus 栈 → KServe。
  • 两者可以混用:KServe 起 LLM,Ray Serve 起 RAG orchestrator。

Q3:prefix caching 和 LMCache 有什么区别?

vLLM 的 --enable-prefix-caching副本内的 HBM 级 KV 复用;LMCache 是跨副本 / 分层(HBM → DRAM → NVMe → 对象存储)的 KV 复用。前者零成本开启,后者需要额外网络和存储。

Q4:Triton 和 vLLM OpenAI Server 能共存吗?

可以,且常见。Triton 跑 CV / ASR / TTS / embedding(强 batching),vLLM 跑 LLM。前面用同一个网关屏蔽差异。

Q5:多租户 LoRA 有性能损耗吗?

有。吞吐下降大约 5–15%(依 adapter 数、rank、SGMV kernel 优化程度),但比起每个 LoRA 起一副基座副本节省 10–100 倍显存,性价比极高。

Q6:我能在昇腾 910B 上跑 KServe 吗?

可以。用华为的 MindIE Service 镜像作为 ServingRuntime 即可。注意 device plugin 要换成 ascend-device-plugin,资源名是 huawei.com/Ascend910

Q7:为什么 GPU 利用率看起来不高但延迟已经爆了?

DCGM 报告的 GPU_UTIL 只看"SM 是否在活动",不代表算力打满。LLM decode 阶段是访存 bound,SM 大多时候在等 HBM,GPU_UTIL 可能长期 40–60%,但HBM 带宽利用DCGM_FI_PROF_DRAM_ACTIVE)已经 90%+。排查时同时看算力利用、带宽利用、NCCL 通信时长、vllm:kv_cache_usage_percvllm:num_requests_waiting

Q8:vLLM 升级版本要怎么做?

强烈建议"镜像 + 权重 + 配置"一起锁版本,按 KServe / K8s 标准 RollingUpdate 做滚动。新版本先用 1 副本承接 1% 流量,跑 30 分钟没 error rate / p99 异常再放量。不要在高峰期升级,vLLM 偶尔有 kernel 兼容性回退(如 FlashAttention 版本)。

Q9:如何阻止单个租户把整个集群打爆?

网关层(下一篇)做 QPS / token/s / 并发三维限流;服务层可按 tenant 在 vLLM 启动参数里给 --max-num-seqs 限制,或者干脆给大客户独占副本。

Q10:推理服务的 SLI / SLO 怎么定?

给出一组经验值,作为起点而非教条:

  • Availability:99.9%(月度),核心主链路 99.95%。
  • TTFT p99:Chat ≤ 2s,RAG ≤ 4s,长文档 ≤ 8s。
  • ITL p99:≤ 80 ms(用户视觉上的"流畅"阈值 ≈ 12 token/s)。
  • Error rate:< 0.1%(区分用户错误 4xx 与服务错误 5xx)。
  • Cost per 1M tokens:按模型分档,定期复盘。

SLO 要和网关、业务双向对齐:业务提诉求 → 服务层给出可行性 → 网关兜底降级路径。

十八、小结

推理服务化的本质,是把 11–16 篇"引擎"变成"云"。你在单机上关心的 paged KV、continuous batching、speculative decoding,到了集群里就变成了自动扩缩、session 路由、PD 分离、多租户 LoRA、跨 region 灾备。引擎是发动机,服务层是底盘。

这一层有三条重要趋势:

  1. KServe + vLLM 成为开源事实默认,国内私有化部署八成以上是这个组合。
  2. PD 分离从论文走向主流,Mooncake 之后,vLLM / SGLang / 各家自研都在做;下一步是 MoE expert 分离。
  3. Serverless GPU 商业化成熟,长尾模型、尖峰流量、batch 任务会越来越多地跑在 Modal / RunPod / 火山方舟这类托管上。
  4. KV cache 成为一等公民:从副本内到跨副本、从 HBM 到冷存,KV 管理正在独立演化出类似"缓存 / 存储"子产品形态(Mooncake Store、LMCache、NIXL)。
  5. 异构硬件混部:同一集群里 H100 / H20 / 昇腾 / MI300 各司其职,上层用统一 API 屏蔽;这对服务层的路由和拓扑感知提出更高要求。

下一篇我们抬高一层,看大模型网关:鉴权、配额、路由、审计、合规、成本——所有和"谁在用、用多少、合不合规"相关的事都在那里。


上一篇工具调用与 MCP 下一篇:[大模型网关]quant67.com/post/llm-in…

十九、延伸阅读线索

  • vLLM production-stack:vLLM 社区维护的生产参考实现,含 Router、Autoscaler、LMCache 集成,Helm Chart 开箱。
  • Nvidia Dynamo:2025 年 Nvidia 开源的推理编排框架,定位是"Triton 的下一代",原生支持 PD 分离、NIXL、多引擎。
  • Mooncake 开源仓库:KV Store 实现、跨节点 RDMA 传输、KV-aware 调度都能读到源码。
  • Ray Serve LLMray.serve.llm(Ray 2.40+)原生 LLM 抽象,比自己写 deployment 更方便。
  • KServe v0.14+:对 LLM、Hugging Face 模型的一等公民支持,持续迭代。

这些都是本文没法展开但强烈建议读的"下一步"。

参考资料

  1. NVIDIA Triton Inference Server 文档 — github.com/triton-infe…
  2. Ray Serve 官方文档 — docs.ray.io/en/latest/s…
  3. KServe 官方文档 — kserve.github.io/website/
  4. KEDA 官方文档 — keda.sh/
  5. Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving(Moonshot AI, 2024)
  6. DistServe: Disaggregating Prefill and Decoding for Goodput-Optimized LLM Serving(OSDI 2024)
  7. Splitwise: Efficient Generative LLM Inference Using Phase Splitting(Microsoft, ISCA 2024)
  8. S-LoRA: Serving Thousands of Concurrent LoRA Adapters(UCB, 2023)
  9. Punica: Multi-Tenant LoRA Serving(CMU, 2023)
  10. vLLM Production Stack — github.com/vllm-projec…
  11. LMCache — github.com/LMCache/LMC…
  12. BentoML / OpenLLM — github.com/bentoml/Ope…
  13. 阿里云 PAI-EAS / 火山 veMLP / 华为 MindIE 官方文档
  14. Volcano / Koordinator / Kueue K8s 调度器文档
  15. Modal / RunPod / Replicate / Fly Machines 产品文档