6.1 模型服务化架构:KServe、Triton 与 Ray Serve 一个训练好的模型文件本身没有任何价值——只有被包装成「服务」,能接收请求、返回预测、被业务系统调用,它才产生价值。模型服务化架构就是这层「包装」,它让模型从文件变成 API。 6.1.1 模型服务化的核心问题 把模型变成服务,表面看只是「加载模型 + 暴露 HTTP 端点」,但生产级模型服务要解决的问题远不止于此: 问题 | 说明 协议 | 用什么协议接收请求?输入输出格式怎么定? 多框架支持 | PyTorch、TensorFlow、ONNX、TensorRT 模型怎么都能跑? 资源管理 | 模型占多少 GPU/内存?多模型如何共享资源? 弹性扩缩 | 流量涨了怎么扩?流量跌了怎么缩?
一个训练好的模型文件本身没有任何价值——只有被包装成「服务」,能接收请求、返回预测、被业务系统调用,它才产生价值。模型服务化架构就是这层「包装」,它让模型从文件变成 API。
把模型变成服务,表面看只是「加载模型 + 暴露 HTTP 端点」,但生产级模型服务要解决的问题远不止于此:
| 问题 | 说明 |
|---|---|
| 协议 | 用什么协议接收请求?输入输出格式怎么定? |
| 多框架支持 | PyTorch、TensorFlow、ONNX、TensorRT 模型怎么都能跑? |
| 资源管理 | 模型占多少 GPU/内存?多模型如何共享资源? |
| 弹性扩缩 | 流量涨了怎么扩?流量跌了怎么缩? |
| 流量管理 | 灰度、A/B、金丝雀、流量切分怎么做? |
| 生命周期 | 模型版本如何更新?回滚? |
| 可观测性 | 推理延迟、吞吐、错误率怎么监控? |
围绕这些问题,业界演化出了三类推理框架,反映了不同的设计哲学:
理解这三者的定位差异,是选型的前提。
KServe(原 KFServing)是 CNCF 项目,是 K8s 上推理服务的事实标准。它的核心是定义了 InferenceService CRD——一个声明式的「推理服务」抽象。
InferenceService 把一个推理服务拆成三个组件:
# InferenceService 伪声明(示意) apiVersion: serving.kserve.io/v1beta1 kind: InferenceService metadata: name: llm-service spec: predictor: containers: - name: vllm image: vllm/vllm-openai:latest resources: limits: nvidia.com/gpu: 1
KServe 的核心价值是「抽象与标准」:
💡 判读:KServe 的本质是「推理服务的 K8s 抽象层」,它不直接做推理,而是把推理交给底层引擎(vLLM、Triton、SKLearn Server 等)。这种分层让 KServe 专注于「服务治理」(流量、扩缩、协议),把「推理优化」交给专业引擎。
Triton Inference Server 是 NVIDIA 出品的通用推理服务器,强项是「多框架支持」与「性能优化」。
Triton 能在一个服务器内同时跑多种框架的模型:
这种能力对「模型 zoo」团队极有价值——历史上有多种框架训出的模型,都可以用同一个 Triton 实例服务,无需为每种框架单独部署。
Triton 用 模型仓库 管理模型。仓库是一个目录结构,每个模型有自己的文件夹:
model_repo/ ├── bert_model/ │ ├── config.pbtxt # 模型配置 │ ├── 1/ # 版本 1 │ │ └── model.pt │ └── 2/ # 版本 2 │ └── model.pt └── resnet_model/ ├── config.pbtxt └── 1/ └── model.onnx
Triton 支持模型的多版本管理,可以同时加载多个版本,按版本路由请求。这与第 4 章模型注册中心的概念呼应——注册中心管模型版本,Triton 加载并服务这些版本。
Triton 内置多种性能优化:
| 维度 | Triton |
|---|---|
| 多框架 | 极强(TF/PyTorch/ONNX/TRT) |
| 性能优化 | 强(Dynamic Batching、TRT) |
| 模型仓库 | 内建版本管理 |
| K8s 集成 | 通过 KServe 或独立部署 |
| LLM 专用 | 弱(需配合 TensorRT-LLM) |
| 适合 | 多框架模型 zoo、传统 ML/DL |
Ray Serve 是 Ray 框架的推理服务组件,与第 5 章 5.2 节的 Ray Train 同属 Ray 生态。它的核心是「编程式 API」——用 Python 直接定义推理服务,无需 YAML。
# Ray Serve 风格伪代码(示意) from ray import serve @serve.deployment(num_replicas=3, ray_actor_options={"num_gpus": 1}) class MyModel: def __init__(self): self.model = load_model() def __call__(self, request): return self.model.predict(request.data) serve.run(MyModel.bind())
Ray Serve 的特点:
num_replicas 自动管理多副本。Ray Serve 的强项是「Python 优先 + Ray 生态」,适合「训练 + 推理一体化」的 ML 平台场景。它的弱项是与 K8s 原生生态(如 KEDA、Istio)集成不如 KServe 深度。
| 维度 | KServe | Triton | Ray Serve |
|---|---|---|---|
| 定位 | K8s 推理服务抽象 | 多框架推理服务器 | 编程式推理服务 |
| 范式 | 声明式 CRD(YAML) | 配置文件 + 容器 | Python API |
| 多框架 | 通过多种 Server | 极强 | 主要 PyTorch/HF |
| LLM 专用 | 通过 vLLM/TGI Server | 通过 TensorRT-LLM | 通过 vLLM |
| K8s 集成 | 原生 | 通过 KServe/独立 | 通过 Ray Operator |
| Serverless | 强(scale-to-zero) | 一般 | 一般 |
| 流量管理 | 内建 Canary/A/B | 一般 | 一般 |
| 适合 | K8s 优先的推理平台 | 多框架模型 zoo | Ray 全栈团队 |
理解这三者的关键,是分清「服务框架」与「推理引擎」两个层次:
二者是正交且可组合的。最常见的生产组合是:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 320" font-family="sans-serif" font-size="13"> <text x="400" y="24" text-anchor="middle" font-size="15" font-weight="bold">服务框架与推理引擎的分层组合</text> <!-- 业务请求层 --> <rect x="100" y="50" width="600" height="50" rx="6" fill="#fef9c3" stroke="#ca8a04"/> <text x="400" y="80" text-anchor="middle" font-weight="bold">业务请求 / API 网关</text> <!-- 服务框架层 --> <rect x="100" y="120" width="600" height="60" rx="8" fill="#dbeafe" stroke="#2563eb"/> <text x="400" y="145" text-anchor="middle" font-weight="bold">服务框架层:流量、扩缩、协议、生命周期</text> <text x="400" y="168" text-anchor="middle" font-size="11">KServe(K8s 原生) · Ray Serve(编程式)</text> <!-- 推理引擎层 --> <rect x="100" y="200" width="600" height="60" rx="8" fill="#fce7f3" stroke="#db2777"/> <text x="400" y="225" text-anchor="middle" font-weight="bold">推理引擎层:模型加载、批处理、显存优化</text> <text x="400" y="248" text-anchor="middle" font-size="11">vLLM(LLM 专用) · TGI · Triton(多框架) · TensorRT-LLM</text> <!-- 箭头 --> <line x1="400" y1="100" x2="400" y2="120" stroke="#475569" stroke-width="2" marker-end="url(#arr7)"/> <line x1="400" y1="180" x2="400" y2="200" stroke="#475569" stroke-width="2" marker-end="url(#arr7)"/> <text x="400" y="295" text-anchor="middle" font-size="11" fill="#16a34a" font-style="italic">常见组合:KServe(服务框架) + vLLM(推理引擎) = LLM 生产主流</text> <defs> <marker id="arr7" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"> <path d="M0,0 L8,3 L0,6 z" fill="#475569"/> </marker> </defs> </svg>
💡 判读:理解了「服务框架 + 推理引擎」的分层,就理解了为什么 KServe 与 vLLM 不是竞争关系——它们处于不同层次,KServe 是「外层治理」,vLLM 是「内层优化」。一个完整的 LLM 推理服务,往往两者都需要。
KServe 定义了一套标准的推理协议(KServe v2 / Open Inference Protocol),让推理服务有统一的接口约定。核心端点:
/v2/health/live:健康检查。/v2/health/ready:就绪检查。/v2/models/{model_name}/infer:推理请求。推理请求/响应的 JSON 格式标准化(基于 tensors):
// 请求示意 { "inputs": [ {"name": "input_0", "shape": [1, 10], "datatype": "FP32", "data": [...]} ] } // 响应示意 { "outputs": [ {"name": "output_0", "shape": [1, 2], "datatype": "FP32", "data": [...]} ] }
这套协议让客户端无需关心底层是 vLLM 还是 Triton,只要按 v2 协议请求即可。这对「模型后端切换」极有价值——今天用 vLLM,明天换 TGI,客户端代码不用改。
⚠️ LLM 协议:需要注意的是,KServe v2 协议是为传统 ML 设计的(tensors 进 tensors 出),LLM 的「OpenAI 兼容 API」(chat/completions 端点、流式输出)是另一套协议。vLLM、TGI 都同时支持 OpenAI 兼容协议,这是 LLM 时代的实际标准。
给一个选型决策树:
💡 选型经验总结:
- LLM 生产部署 → KServe + vLLM(主流、成熟、生态广)。
- Ray 全栈团队 → Ray Serve + vLLM(统一 Ray 生态)。
- 多框架模型 zoo → KServe + Triton(一个 Triton 跑多框架)。
- 追求极致 NVIDIA 优化 → Triton + TensorRT-LLM。
- 不确定时选 KServe + vLLM,这是当前最稳的 LLM 推理组合。
推理服务在 K8s 上的几种部署模式:
最简单的模式:一个推理 Pod 独占一张 GPU。适合 LLM 这种显存需求大的场景。缺点是 GPU 利用率可能不高。
用第 3 章 3.1 节的 MPS/MIG 让多个推理副本共享一张 GPU。适合小模型、多副本提升吞吐。
KServe 支持空闲时缩容到零副本,请求来时再拉起。适合流量稀疏的场景,但 LLM 冷启动慢(模型加载需数十秒),需谨慎。
多个可用区部署,用全局负载均衡分发流量。适合高可用、低延迟要求的场景。
| 部署模式 | GPU 利用率 | 冷启动 | 适合 |
|---|---|---|---|
| 单副本独占 | 中 | 快 | LLM 大模型 |
| 多副本共享 | 高 | 快 | 小模型、高 QPS |
| Serverless | 极高 | 慢 | 流量稀疏 |
| 异地多活 | 中 | 快 | 高可用 |
最后要强调,模型推理服务化只是「完整推理链路」的一环。一个完整的推理请求通常经过:
客户端 → 网关 → 特征拉取 → 预处理 → 模型推理 → 后处理 → 业务逻辑 → 响应
理想情况下,这些步骤应该打包成统一的推理服务(KServe 的 Transformer 组件就是为此设计),让训练与推理共用同一份预处理代码,从根上消除 training-serving skew(呼应第 4 章 4.2 节)。
下一节《6.2 自回归推理的 KV Cache 困境》将深入 LLM 推理为什么慢、瓶颈在哪。