【推理引擎】大模型推理服务部署、性能调优与生产实践:SGLang、vLLM、TensorRT-LLM
文章目录
- 【推理引擎】大模型推理服务部署、性能调优与生产实践:SGLang、vLLM、TensorRT-LLM
-
- 一、推理引擎:选型与运行原理(SGLang、vLLM、TensorRT-LLM)
-
- 1. 推理引擎解决什么问题
- 2. 三种引擎的关键执行路径
- 3. 前缀缓存与 KV Cache
- 二、模型部署:环境准备、服务部署与 API 调用
-
- 1. 环境与版本检查
- 2. SGLang Docker 单机部署
- 3. vLLM Docker 部署
- 4. TensorRT-LLM Engine 构建与服务
- 5. Kubernetes 部署骨架(以 SGLang 为例)
- 6. 从网关访问推理服务
- 7. OpenAI 兼容 API 调用
- 8. 采样参数如何影响结果
- 9. 使用引擎原生前端
- 三、性能调优:从显存到吞吐(指标、量化与 PD 分离)
-
- 1. 先建立正确的性能指标
- 2. 显存预算与上下文长度
- 3. Tensor Parallel、Data Parallel 与副本
- 4. 调度和前缀缓存调优
- 5. PD 分离:把 Prefill 与 Decode 拆成独立服务池
- 6. 与 PD 分离配套的进阶优化
- 7. 量化、FlashInfer 与 Kernel 选择
- 四、生产实践:生产治理、监控与排障
-
- 1. 监控和日志
- 2. 告警和弹性策略
- 3. 发布、升级与安全边界
- 4. 常见故障排查
- 5. 常见问答
- 6. 一份上线检查清单
- 五、平台化演进:多模型、多租户、容量与成本治理
-
- 1. 多模型注册与智能路由
- 2. 多租户隔离、配额与公平调度
- 3. 容量规划与单位 Token 成本
- 4. 异构 GPU、Engine 兼容与多地域容灾
- 5. 从单服务到推理平台的演进路线
把一个大模型跑起来,只能证明模型能推理;把它作为线上服务稳定地提供给多个调用方,还要解决显存、并发、流式输出、模型加载、监控和故障恢复等问题。
SGLang、vLLM 和 TensorRT-LLM 都是面向大语言模型和多模态模型的推理引擎。它们通常提供 OpenAI 兼容接口,也会在请求调度、KV Cache、批处理、量化和 GPU Kernel 等层面做优化。推理引擎的核心价值不是“把模型包一层 HTTP”,而是把模型权重、请求队列和 GPU 执行组织成可持续优化的运行时。
本文以 Qwen、Llama 等 Hugging Face 格式模型为例,说明 SGLang、vLLM 和 TensorRT-LLM 的定位差异、部署方式、关键参数和生产排障路径。命令中的版本、模型名和 GPU 数量需要按实际环境替换,生产环境应固定推理引擎、CUDA、驱动和模型 revision,而不是直接使用 latest。

一、推理引擎:选型与运行原理(SGLang、vLLM、TensorRT-LLM)
1. 推理引擎解决什么问题
一个推理请求通常经历以下阶段:读取聊天消息、分词、构造 KV Cache、调度批次、执行 Prefill、逐 Token Decode、采样并返回结果。并发一高,真正的瓶颈往往不是模型前向本身,而是请求排队、显存碎片、重复计算和不同长度请求之间的相互阻塞。
三种引擎都将这些通用能力放入 runtime,并在其上提供在线 API 或编程入口:
| OpenAI 兼容 API | 通过 /v1/chat/completions、/v1/completions 提供在线推理 | 接入现有 SDK、网关和业务服务 |
| 引擎原生 API | 用 SGLang Python 前端、vLLM Python API 或 TensorRT-LLM Runtime 编排推理 | Agent、离线批处理、复杂生成逻辑 |
三种引擎的优化侧重点并不完全相同:
| 服务接口 | OpenAI 兼容 API + Python 前端 | OpenAI 兼容 API + Python API | TensorRT-LLM Runtime + trtllm-serve 等服务入口 |
| 核心优化 | RadixAttention 前缀缓存、连续批处理、结构化生成 | PagedAttention、连续批处理、广泛模型适配 | TensorRT-LLM Engine、融合 Kernel、量化和 CUDA Graph |
| 典型优势 | 多轮对话、重复前缀和结构化生成 | 通用在线服务、生态成熟、上手快 | NVIDIA GPU 上追求极致吞吐和低延迟 |
| 主要代价 | 版本变化快,需要验证模型适配 | 特定模型和场景未必达到最优 | Engine 构建、版本绑定和部署复杂度更高 |
| 选型建议 | 用真实业务压测 TTFT、TPOT、缓存命中率和成本 | 用真实业务压测吞吐、P99 和运维成本 | 用目标 GPU、目标精度和固定模型构建后再比较 |
这里的比较不是为了证明哪个框架“绝对更快”。模型架构、输入长度、输出长度、并发度、GPU 型号和量化方式都会改变结果。
2. 三种引擎的关键执行路径
客户端 / AI Gateway
│ OpenAI API 或引擎原生请求
▼
SGLang / vLLM / TensorRT-LLM Server
├─ 请求解析、鉴权边界和参数校验
├─ Tokenizer 与 Prefill 调度
├─ Prefix Cache 或 Paged KV Cache 查询
├─ Continuous Batching 动态组批
├─ GPU Worker 执行 Prefill 与 Decode
└─ SSE 流式返回 Token
│
├─ /health、/metrics、运行日志
└─ Prometheus、Grafana、日志平台
Prefill 负责一次性处理输入上下文,计算量大,主要影响首 Token 延迟(TTFT);Decode 按 Token 迭代生成,主要影响每 Token 延迟(TPOT)和输出吞吐。SGLang 更强调 RadixAttention 前缀复用,vLLM 以 PagedAttention 管理 KV Cache,TensorRT-LLM 则依赖构建好的 Engine、融合 Kernel 和 CUDA Graph。把长上下文请求和短请求混在一起时,三种引擎都需要在吞吐与交互延迟之间做取舍。
3. 前缀缓存与 KV Cache
多轮对话、系统提示词和批量文档问答经常共享一段前缀。如果每次请求都从头计算,GPU 会重复执行相同的 Prefill。SGLang 的 RadixAttention 会将已计算的 Token 前缀组织成可复用的树结构;vLLM 也支持 Prefix Caching,但实现和参数名称随版本变化;TensorRT-LLM 则通常结合 KV Cache 管理、Paged Context FMHA 和 CUDA Graph 等能力优化执行。
前缀缓存能否生效,取决于输入 Token 是否真的相同:系统提示词的空格、工具描述的排序、消息序列化方式和模板版本发生变化,都会导致缓存未命中。因此应固定 Chat Template,把稳定内容放在前面,把用户动态内容放在后面,并在指标中观察命中率,而不是只凭感觉判断。
缓存不是无限的。推理引擎会在显存预算内管理 KV Cache,缓存过多会挤压模型权重和新请求空间。生产环境需要同时关注缓存命中率、KV Cache 使用率、请求排队时间和 OOM 次数。不要把 SGLang 的缓存参数直接照搬到 vLLM 或 TensorRT-LLM,应以实际版本的启动帮助和指标为准。
二、模型部署:环境准备、服务部署与 API 调用
本章按照模型服务从准备到可调用的顺序展开:先校验运行环境,再分别启动三种推理引擎,最后通过统一 API 和网关完成验证。
1. 环境与版本检查
上线前先记录以下信息,后续排障时不要只看“CUDA 能不能用”:
nvidia-smi
python3 –version
python3 -c 'import torch; print(torch.__version__, torch.version.cuda, torch.cuda.device_count())'
需要确认的兼容关系包括:NVIDIA 驱动是否支持目标 CUDA、PyTorch 与推理引擎的 CUDA 构建是否匹配、GPU 显存是否能容纳模型权重和 KV Cache、跨卡连接是否具备 NVLink 或高速 PCIe,以及容器的 /dev/shm 是否足够。TensorRT-LLM 还要额外校验 TensorRT、CUDA、驱动和 Engine 构建环境的一致性。
模型下载目录最好使用本地 NVMe 或高性能共享存储,并提前完成权限、校验和缓存。第一次启动会加载权重、初始化 CUDA Kernel 和建立通信组,不能把“首次启动时间”当作正常请求延迟。
2. SGLang Docker 单机部署
开发和压测可以使用官方镜像。生产环境把 <version> 替换为经过验证的固定标签,并将模型通过只读卷挂载到容器:
docker run –rm –gpus all \\
–ipc=host \\
–shm-size=32g \\
–network host \\
-v /data/models/Qwen2.5-32B-Instruct:/models/Qwen2.5-32B-Instruct:ro \\
lmsysorg/sglang:<version> \\
python3 -m sglang.launch_server \\
–model-path /models/Qwen2.5-32B-Instruct \\
–served-model-name qwen2.5-32b \\
–host 0.0.0.0 \\
–port 30000 \\
–tp-size 4 \\
–context-length 32768 \\
–mem-fraction-static 0.85 \\
–enable-metrics
几个参数的含义:
| –model-path | 本地目录或 Hugging Face 模型路径 | 生产使用固定 revision 的本地副本 |
| –served-model-name | API 中暴露的模型名 | 与网关路由和计费口径保持一致 |
| –tp-size | Tensor Parallel 并行度 | 通常与参与推理的 GPU 数量一致 |
| –context-length | 单请求最大上下文长度 | 按业务需要设置,越大越占 KV Cache |
| –mem-fraction-static | 静态显存预算比例 | 留出通信、运行时和碎片空间后再提高 |
| –enable-metrics | 暴露 Prometheus 指标 | 生产环境应默认开启并纳入告警 |
–tp-size 4 并不意味着四张卡一定比一张卡快。Tensor Parallel 会引入跨卡通信,GPU 拓扑、模型大小和请求长度都会影响收益。小模型在 PCIe 机器上强行扩大 TP,可能反而降低吞吐。
3. vLLM Docker 部署
vLLM 可以通过 OpenAI-compatible server 直接提供统一的 /v1 接口。下面的命令适合单机压测或作为 Kubernetes 容器的启动参数;vllm/vllm-openai 的镜像标签和参数会随版本变化,正式部署前应以对应版本的 vllm serve –help 为准。
docker run –rm –gpus all \\
–ipc=host \\
–shm-size=32g \\
–network host \\
-v /data/models/Qwen2.5-32B-Instruct:/models/Qwen2.5-32B-Instruct:ro \\
vllm/vllm-openai:<version> \\
–model /models/Qwen2.5-32B-Instruct \\
–served-model-name qwen2.5-32b \\
–host 0.0.0.0 \\
–port 30000 \\
–tensor-parallel-size 4 \\
–max-model-len 32768 \\
–gpu-memory-utilization 0.85
vLLM 的 –tensor-parallel-size 与 SGLang 的 –tp-size 语义相近,但不能混用参数名。Prefix Caching、量化格式、最大并发和调度参数也应按 vLLM 当前版本的帮助信息逐项确认。生产环境建议为镜像、模型 revision 和启动参数建立可回滚的配置清单。
4. TensorRT-LLM Engine 构建与服务
TensorRT-LLM 通常不是启动容器后直接读取 Hugging Face 权重,而是先把模型转换为 checkpoint,再针对目标 GPU、精度和并行策略构建 TensorRT Engine。典型流程如下:
Hugging Face 模型
→ TensorRT-LLM checkpoint 转换
→ trtllm-build 构建 Engine
→ trtllm-serve 或 Triton Inference Server
→ OpenAI 兼容 API / 内部服务
以下命令是版本相关示例,具体的转换脚本路径、参数名和服务入口以所用 TensorRT-LLM 版本文档及 –help 输出为准:
# 1. 将 Hugging Face 权重转换为 TensorRT-LLM checkpoint
python examples/convert_checkpoint.py \\
–model_dir /models/Qwen2.5-32B-Instruct \\
–output_dir /tmp/qwen2.5-32b-ckpt \\
–dtype float16 \\
–tp_size 4
# 2. 针对目标 GPU 构建 Engine;FP16 也可以替换为 BF16、FP8 或 INT8
trtllm-build \\
–checkpoint_dir /tmp/qwen2.5-32b-ckpt \\
–output_dir /engines/qwen2.5-32b-tp4 \\
–gemm_plugin float16
# 3. 启动服务(不同版本可能使用 Triton 或其他 serving 入口)
trtllm-serve /engines/qwen2.5-32b-tp4 \\
–host 0.0.0.0 \\
–port 30000 \\
–served-model-name qwen2.5-32b
Engine 与 GPU 架构、TensorRT-LLM 版本、CUDA 版本和并行配置存在绑定关系。升级其中任一项都应重新构建并回归测试,不能把旧 Engine 直接复制到新运行时。TensorRT-LLM 适合模型、GPU 和精度相对固定且追求极致吞吐的场景;模型频繁变更或需要快速适配新架构时,SGLang、vLLM 通常更易迭代。
5. Kubernetes 部署骨架(以 SGLang 为例)
Kubernetes 中建议一个 Pod 绑定一组固定 GPU,并通过节点标签、RuntimeClass 和 GPU 资源限制保证调度稳定。下面是可作为起点的 Deployment,模型目录假设由 PVC 提供:
apiVersion: apps/v1
kind: Deployment
metadata:
name: sglang–qwen
labels:
app: sglang–qwen
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: sglang–qwen
template:
metadata:
labels:
app: sglang–qwen
spec:
nodeSelector:
accelerator: nvidia–a100
terminationGracePeriodSeconds: 120
containers:
– name: server
image: lmsysorg/sglang:<version>
command: ["python3", "-m", "sglang.launch_server"]
args:
– ––model–path=/models/Qwen2.5–32B–Instruct
– ––served–model–name=qwen2.5–32b
– ––host=0.0.0.0
– ––port=30000
– ––tp–size=4
– ––context–length=32768
– ––mem–fraction–static=0.85
– ––enable–metrics
ports:
– name: http
containerPort: 30000
resources:
limits:
nvidia.com/gpu: "4"
memory: 64Gi
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 10
failureThreshold: 30
livenessProbe:
httpGet:
path: /health
port: http
periodSeconds: 20
failureThreshold: 6
volumeMounts:
– name: model
mountPath: /models
readOnly: true
volumes:
– name: model
persistentVolumeClaim:
claimName: llm–models
—
apiVersion: v1
kind: Service
metadata:
name: sglang–qwen
spec:
selector:
app: sglang–qwen
ports:
– name: http
port: 30000
targetPort: http
模型加载通常需要几十秒到数分钟,readiness 必须在服务真正可以接收请求后才通过。生产发布建议使用新旧 Deployment 并行预热,再由网关切流;直接滚动重启唯一副本会造成较长不可用窗口。模型文件如果通过 Init Container 下载,要设置下载超时、校验和以及断点续传,避免每次重启都从公网重新拉取。
6. 从网关访问推理服务
三种推理服务都适合放在内网,外部鉴权、租户限流、配额和审计交给 AI Gateway。最少应在网关层补齐以下字段:request_id、trace_id、tenant、model、stream 和 max_tokens。这样才能把一次调用和指标、日志、Trace 关联起来。
7. OpenAI 兼容 API 调用
启动服务后,可以使用 curl 验证非流式接口:
curl http://127.0.0.1:30000/v1/chat/completions \\
-H 'Content-Type: application/json' \\
-d '{
"model": "qwen2.5-32b",
"messages": [
{"role": "system", "content": "你是一个严谨的运维助手。"},
{"role": "user", "content": "解释一次 API 延迟升高的排查顺序。"}
],
"temperature": 0.2,
"top_p": 0.9,
"max_tokens": 512,
"stream": false
}'
流式响应通过 SSE 返回,适合聊天界面和长文本生成:
curl -N http://127.0.0.1:30000/v1/chat/completions \\
-H 'Content-Type: application/json' \\
-d '{
"model": "qwen2.5-32b",
"messages": [{"role": "user", "content": "用三点说明 SGLang 的前缀缓存。"}],
"max_tokens": 256,
"stream": true
}'
业务服务也可以复用 OpenAI SDK,只需把 base_url 指向对应推理服务:
from openai import OpenAI
client = OpenAI(
base_url="http://inference-qwen:30000/v1",
api_key="internal-token",
)
response = client.chat.completions.create(
model="qwen2.5-32b",
messages=[{"role": "user", "content": "写一个 PostgreSQL 索引检查清单。"}],
temperature=0.1,
max_tokens=512,
)
print(response.choices[0].message.content)
三种引擎都提供不同程度的 OpenAI 兼容能力,但不等于所有 OpenAI 参数在所有模型和版本上都完全一致。接入前应建立参数兼容性测试,重点验证 stop、工具调用、JSON 输出、视觉输入、流式中断和错误码。
8. 采样参数如何影响结果
| temperature | 调整采样随机性 | 分类、抽取等任务使用低值;创作任务再提高 |
| top_p | nucleus sampling 截断范围 | 通常只调一个随机性参数,避免组合失控 |
| max_tokens | 最大输出 Token 数 | 由业务上限控制,防止长输出占满并发 |
| stop | 提前结束生成的字符串 | 与模板和流式协议一起测试 |
| stream | 是否分片返回 | 长响应使用流式,但网关要正确处理断连 |
对结构化输出,优先使用模型和框架支持的 JSON Schema、正则或 choices 约束,并在服务端做最终 JSON 校验。不要只在 Prompt 中写“必须输出 JSON”,然后把未经校验的文本直接写入数据库。
9. 使用引擎原生前端
当流程包含多个生成步骤、候选选择或共享前缀时,引擎原生前端可以把编排逻辑放到服务端。下面以 SGLang 为例,vLLM 和 TensorRT-LLM 可使用各自的 Python API 或 Runtime:
import sglang as sgl
@sgl.function
def classify_and_explain(s, question):
s += "问题:" + question + "\\n"
s += "类别:" + sgl.gen("category", choices=["故障", "配置", "性能", "其他"]) + "\\n"
s += "解释:" + sgl.gen("explanation", max_tokens=256)
这类编排适合固定流程和可复用前缀。动态 Agent 仍应设置步骤数、总 Token、工具调用次数和超时,避免模型在服务端无限循环。
三、性能调优:从显存到吞吐(指标、量化与 PD 分离)
1. 先建立正确的性能指标
只看平均响应时间会掩盖排队和长尾问题。在线推理至少记录:
| TTFT | 请求到首个输出 Token 的时间 | 排队、Prefill、输入长度、前缀缓存 |
| TPOT | 相邻输出 Token 的平均间隔 | Decode、GPU 利用率、并发和采样 |
| E2E Latency | 请求开始到完成的总时间 | TTFT、输出长度、网络和客户端读取 |
| Throughput | 每秒生成 Token 或完成请求数 | 批处理、模型大小、并发和 GPU |
| Queue Time | 进入队列到开始执行的时间 | 并发上限、调度策略和突发流量 |
| Cache Hit Rate | 前缀缓存命中比例 | Prompt 稳定性和缓存容量 |
压测时固定模型 revision、输入输出长度和并发曲线,分别测冷启动、缓存命中、单请求、稳定并发和突发流量。把 P50、P95、P99 与 GPU 显存、功耗、温度、PCIe/NVLink 通信一起记录,才能判断是模型计算慢还是排队慢。
2. 显存预算与上下文长度
显存大致由四部分构成:模型权重、运行时临时张量、KV Cache 和通信/框架开销。量化只主要降低权重占用,不会按相同比例消除 KV Cache;当上下文很长、并发很高时,KV Cache 仍然可能成为瓶颈。
常用调优顺序如下:
发生 OOM 时,不要只重启 Pod。先确认是启动阶段权重 OOM、运行阶段 KV Cache OOM,还是长尾请求触发的碎片问题,再分别调整 TP、上下文、并发和量化配置。
3. Tensor Parallel、Data Parallel 与副本
Tensor Parallel(TP)把同一个模型拆到多张 GPU 上,适合单卡放不下或需要更高单实例吞吐的模型;代价是每一步都可能发生跨卡通信。Data Parallel(DP)是多个推理副本共同承接请求,适合模型能够放入每组 GPU、并且希望提升整体并发的场景。
可以按下面的方式做容量设计:
单 Pod 使用 GPU 数 = TP × DP
集群总容量 = 单 Pod 每秒生成 Token × Pod 数量
稳定并发上限 ≈ 可接受排队时间内的处理能力
在有 NVLink 的机器上,优先让 TP 跨同一互联域;跨 NUMA、跨主机的 TP 需要高速网络和 NCCL 配置,不能照搬单机参数。若模型能在单卡或小 TP 上运行,通常增加多个副本比继续扩大 TP 更容易获得线性吞吐。
4. 调度和前缀缓存调优
连续批处理会在每轮 Decode 中动态加入新请求、移除已完成请求,提高 GPU 空闲时间的利用率。但并发不是越大越好:过大的批次会增加 TTFT 和长尾,过小的批次又无法发挥 GPU 吞吐。
建议建立两类服务池:交互池优先保证 TTFT 和 P99,离线池优先追求每秒 Token;不要让批量评测或长文本总结占满交互池。对共享系统提示词和工具定义,固定模板和字段顺序,观察缓存命中率;命中率低时先检查 Prompt 拼接逻辑,再调整缓存预算。
5. PD 分离:把 Prefill 与 Decode 拆成独立服务池
PD 分离(Prefill/Decode Disaggregation,预填充与解码分离)确实属于性能调优实践,但它更接近“部署架构级调优”,而不是单个启动参数。Prefill 需要一次性处理大量输入 Token,通常更偏计算密集;Decode 每轮只生成少量 Token,更容易受显存带宽、KV Cache 访问和调度抖动影响。两者混在同一个实例时,长上下文 Prefill 可能挤占 Decode 的执行机会,导致 TTFT、TPOT 互相影响。
典型的 PD 架构如下:
客户端
│
▼
AI Gateway / PD Router
├─ Prefill Pool:处理输入 Token,生成 KV Cache
│ │ KV Transfer(RDMA / NVLink / 高速网络)
│ ▼
└─ Decode Pool:加载或接收 KV Cache,持续生成 Token 并返回 SSE
PD 分离的价值在于可以分别扩缩容和设置资源配额。例如,输入上下文很长但输出较短的知识库问答,可以增加 Prefill 副本;聊天和代码补全输出较长,则可以增加 Decode 副本。路由器还可以按租户、模型、上下文长度和服务等级把请求送入不同资源池。
SGLang、vLLM 和 TensorRT-LLM 对 PD 分离、KV Transfer Connector、远程 KV Cache 和 Triton 编排的支持方式并不相同,部分能力仍处于实验或快速演进阶段。不要只看到文档中的功能名就直接上线,应确认目标版本是否支持当前模型、并行方式和网络拓扑,并完成端到端压测。
| 负载特征 | 长上下文、Prefill 和 Decode 资源需求差异明显 | 单请求、短上下文、并发很低 |
| 目标 | 同时压低 TTFT 和 TPOT,或需要独立扩缩容 | 只追求单请求最低延迟 |
| 网络 | 具备低延迟、高带宽的 NVLink、RoCE 或 InfiniBand | 仅有普通跨机网络,KV 传输占比高 |
| 运维 | 有成熟的路由、预热、故障转移和容量治理 | 团队尚未建立多池发布和排障能力 |
落地时至少观测四类数据:Prefill 排队时间、Decode 排队时间、KV 传输字节数与耗时、端到端 TTFT/TPOT。只有当“减少互相干扰”带来的收益大于 KV 传输和额外副本成本时,PD 分离才是正收益。KV 传输失败时应有重试或回退到合并实例的策略,否则一个网络抖动就可能放大为整条请求链路失败。
6. 与 PD 分离配套的进阶优化
PD 分离之外,还有几类经常组合使用的优化。它们解决的问题不同,不能简单叠加后期待线性收益:
| Chunked Prefill | 长输入一次 Prefill 阻塞 Decode | 长上下文和交互请求混部 | 切块过小会增加调度开销,TTFT 可能变长 |
| Speculative Decoding | Decode 每步生成速度不足 | 输出较长、草稿模型与目标模型相近 | 需要额外草稿模型,接受率低时收益有限 |
| KV Cache 分层/卸载 | GPU 显存不足、并发受限 | 长会话、低频缓存和超长上下文 | CPU/NVMe 传输延迟高,需控制冷热数据 |
| Prefix Cache | 重复系统提示词导致 Prefill 重算 | 多轮对话、RAG、工具调用 | Prompt 规范稍有变化就会失效并占用显存 |
| MoE Expert Parallel | MoE 模型专家计算和显存分布不均 | Mixtral、Qwen-MoE 等稀疏模型 | All-to-All 通信和专家负载倾斜 |
| 请求分级与路由 | 长短请求互相影响、突发流量排队 | 交互、批处理、离线任务并存 | 需要网关识别 Token 预算并维护多个服务池 |
Chunked Prefill。
Chunked Prefill 把长输入拆成多个小块,在块与块之间让 Decode 请求获得调度机会。它可以在不完全拆分服务的情况下缓解“长 Prefill 阻塞短请求”,适合先做单实例优化。块大小应通过 TTFT、TPOT 和 GPU 利用率压测确定;并不是越小越好。
Speculative Decoding。
Speculative Decoding 先由较小的草稿模型提出多个候选 Token,再由目标模型批量校验,校验通过的 Token 可以一次提交,从而减少目标模型逐 Token Decode 的轮数。它通常对输出较长、草稿模型与目标模型分布接近的任务更有效;摘要、代码和严格格式输出应分别测量接受率和质量,不能只看理论加速比。
KV Cache 分层与卸载。
可以把 KV Cache 按冷热程度放在 GPU HBM、CPU 内存甚至本地 NVMe 中,或者使用独立的远程 KV Cache 服务。热数据留在 GPU,冷数据在请求再次命中时回迁。该方案能提高可容纳的会话数,但会引入传输延迟和一致性问题;应设置 TTL、容量上限和租户隔离,并把命中率、回迁耗时和淘汰次数纳入监控。
MoE 的 Expert Parallel。
对 Mixture-of-Experts(MoE)模型,Expert Parallel(EP)可以把不同专家分布到不同 GPU,再通过路由只激活部分专家。它与 TP、DP 可以组合,但会增加 All-to-All 通信。优化重点是专家负载均衡、通信拓扑和 batch 组成;当少数专家长期过热时,单纯增加 GPU 数量不一定有效,需要调整路由、容量因子或副本策略。
这些优化建议按“先测量、后改动”的顺序推进:先用统一请求集建立基线,再一次只改变一个变量,记录 TTFT、TPOT、P99、吞吐、GPU 显存、KV Cache 命中率和单位 Token 成本。任何优化都必须有回滚开关,避免性能提升却带来准确率、稳定性或运维复杂度的不可控变化。
7. 量化、FlashInfer 与 Kernel 选择
量化可以降低显存和带宽压力,但不同模型、层和任务对精度敏感度不同。上线前至少比较四项:任务准确率、TTFT、TPOT 和峰值显存。不要仅凭模型文件大小选择量化格式。
SGLang、vLLM 和 TensorRT-LLM 都会根据版本和硬件选择 Attention、采样和通信实现。SGLang、vLLM 常见 FlashInfer、PagedAttention 或 CUDA Graph 后端,TensorRT-LLM 则更多依赖构建 Engine 时确定的融合 Kernel 和 CUDA Graph 配置。遇到升级后性能回退时,应保存启动日志、实际生效的 backend 和 Engine 元数据,使用同一组请求做 A/B 测试,避免同时更换模型、驱动和框架版本。
四、生产实践:生产治理、监控与排障
1. 监控和日志
开启引擎对应的 metrics 选项后,将 SGLang、vLLM 或 Triton/TensorRT-LLM 的指标端点纳入 Prometheus 或 vmagent。Grafana 看板至少应包括:请求数、成功率、5xx、TTFT、TPOT、E2E P99、队列长度、运行中请求数、输入/输出 Token、KV Cache 使用率、缓存命中率和模型加载状态。采用 PD 分离时,还要按 Prefill Pool、Decode Pool 分别展示队列长度、GPU 利用率、处理 Token 数,并记录 KV Transfer 的字节数、耗时、失败率和回退次数。TensorRT-LLM 经 Triton 部署时,还应采集 Triton 的请求队列、批处理和实例级指标。
不同版本的指标名称可能变化,接入时应先抓取 /metrics 确认实际名称,再编写录制规则和告警。不要在看板中硬编码某个版本的指标名而不做升级验证。
日志建议包含以下字段,并传递到 ELK:
{
"timestamp": "2026-09-12T08:30:00Z",
"service": "inference-qwen",
"engine": "sglang",
"model": "qwen2.5-32b",
"request_id": "req-abc123",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"input_tokens": 2048,
"output_tokens": 256,
"ttft_ms": 420,
"status": "ok"
}
模型 Prompt、用户输入和输出内容可能包含隐私或密钥。默认只记录长度、哈希、错误类型和采样后的片段;需要审计全文时单独走权限、脱敏和保留周期,不要把原始内容无条件写入普通日志。
2. 告警和弹性策略
指标告警可以由夜莺或其他告警平台统一管理,典型规则包括:
推理服务进程不可用持续 2 分钟 → Critical
5 分钟 P99 TTFT 超过目标值 → Warning / Critical
KV Cache 使用率持续超过 90% → Warning
GPU 温度、XID、ECC 错误异常 → Critical
5xx 或 OOM 次数在窗口内快速增长 → Critical
请求队列持续增长且无下降趋势 → Warning
KV Transfer 失败率或回退次数持续升高 → Critical
弹性伸缩不要只依据 CPU。推理服务的主要瓶颈往往是 GPU 显存、KV Cache 和队列长度;而新 Pod 的模型加载时间又可能很长。更可靠的方式是:网关按租户和模型限流,使用队列长度或等待时间触发扩容,提前预热备用副本,缩容时先停止接收新请求并等待流式请求完成。
3. 发布、升级与安全边界
生产发布建议采用以下流程:
推理服务不应直接暴露公网。API Key、OAuth、租户配额、请求体大小、模型白名单和审计应放在网关;服务到服务通信使用 mTLS 或内网策略。–trust-remote-code 会允许执行模型仓库中的自定义代码,只有在审核来源和版本后才开启,并将模型目录设置为只读。TensorRT-LLM 的 Engine 文件也应视为受保护的构建产物,只允许来自已审核流水线。
4. 常见故障排查
问题一:服务启动时报 CUDA out of memory。
先区分模型权重无法加载,还是运行时初始化失败。检查模型精度、GPU 显存、TP 数量和是否有其他进程占卡;再降低上下文长度、引擎显存预算或选择量化模型。不要只增加 TP,跨卡通信和模型切分约束可能让问题更复杂。
问题二:GPU 利用率不高,但请求很慢。
优先查看 Queue Time、TTFT 和输入长度。如果队列时间高,说明并发限制或调度策略在等待;如果 Prefill 时间高,检查长上下文和前缀缓存;如果 Decode 间隔高,检查输出长度、批次、采样和 GPU 时钟。CPU Tokenizer、网络发送阻塞和客户端没有及时读取 SSE,也可能让 GPU 看起来不忙。
问题三:多卡启动后卡住或 NCCL 报错。
检查容器是否使用 –ipc=host、共享内存是否足够、各卡驱动和 CUDA 是否一致、NCCL 网卡选择是否正确,以及 Pod 是否被调度到同一台机器。跨主机 TP 还要验证 RDMA、端口、安全组和 NCCL_SOCKET_IFNAME 等配置。
问题四:首 Token 延迟突然升高。
检查是否发生前缀缓存未命中、模型刚重启、长请求突发或 GPU 降频。将系统 Prompt、工具定义和消息模板固定下来,区分冷缓存与热缓存压测;不要只看平均值,要观察 P95/P99 和排队时间。
问题五:流式输出中途断开。
检查网关和负载均衡器的响应超时、SSE 缓冲、客户端取消传播和服务端优雅退出。网关要透传 text/event-stream,定期发送心跳或保持数据刷新,并在取消时及时释放生成请求和 KV Cache。
问题六:结构化输出偶尔不是合法 JSON。
确认使用的模型、推理引擎版本和 API 参数确实支持目标约束;为 JSON Schema、正则和 stop 条件建立回归测试,服务端对结果做解析校验,失败时进行有限次数重试或返回明确错误,不能把校验责任全部交给前端。
问题七:启用 PD 分离后,TTFT 反而升高或请求偶发失败。
先分别查看 Prefill、KV Transfer 和 Decode 三段耗时,确认是否是网络传输、KV Cache 格式不兼容、两侧 TP/PP 配置不一致或路由器重复转发。普通跨机网络下,KV Transfer 可能抵消 Prefill 并行收益;应降低传输距离、使用 RDMA/NVLink,或暂时回退到合并实例。生产上必须保留回退路径,并为转移超时、版本不匹配和目标 Decode 实例不可用设置明确错误码。
5. 常见问答
Q:SGLang、vLLM 和 TensorRT-LLM,哪个一定更快?
A:没有脱离负载的固定答案。SGLang 在共享前缀、多轮对话和结构化生成场景可能优势明显,vLLM 通用服务和模型适配经验丰富,TensorRT-LLM 在固定 NVIDIA GPU 和 Engine 的场景可能取得更高吞吐。最终应使用生产请求分布做压测,至少比较 TTFT、TPOT、P99、吞吐、显存和运维成本。
Q:TP 越大越好吗?
A:不是。SGLang 使用 –tp-size,vLLM 使用 –tensor-parallel-size,TensorRT-LLM 通常在 Engine 构建阶段配置 TP/PP。TP 解决单卡放不下或单实例吞吐不足的问题,但会增加跨卡通信。模型能在单卡或小 TP 上稳定运行时,增加多个副本往往比扩大 TP 更容易提升整体吞吐。
Q:为什么已经开启前缀缓存,命中率还是很低?
A:缓存按 Token 前缀匹配。系统提示词的空格、工具列表顺序、Chat Template、版本字段或动态内容放置位置变化,都会破坏复用。应固定序列化模板,把稳定内容放在前面,并直接查看运行指标确认命中率。
Q:推理服务需要自己实现鉴权吗?
A:服务可以放置最基础的访问控制,但生产上应由 AI Gateway 统一负责 API Key、OAuth、租户限流、配额、审计和模型白名单。三种引擎只暴露在受控网络中,便于升级和隔离。
6. 一份上线检查清单
[ ] 固定推理引擎、PyTorch/TensorRT、CUDA、驱动和模型 revision
[ ] 完成单请求、缓存命中、稳定并发和突发流量压测
[ ] 明确 TP/DP、GPU 拓扑、/dev/shm 和 NCCL 配置
[ ] 设置上下文、输出 Token、并发和请求体大小上限
[ ] readiness 等待模型真正加载完成,发布支持回滚
[ ] /metrics 已接入 Prometheus/vmagent,Grafana 看板可用
[ ] TTFT、TPOT、P99、队列、KV Cache、GPU 和 OOM 已告警
[ ] 若采用 PD 分离,已验证 KV Transfer、网络带宽、回退路径和两侧版本兼容性
[ ] 日志包含 request_id、trace_id、model 和 Token 统计并完成脱敏
[ ] 网关已配置鉴权、限流、SSE 超时和客户端取消传播
[ ] 已演练 OOM、NCCL 故障、模型加载失败和通知失败
五、平台化演进:多模型、多租户、容量与成本治理
单个模型能够稳定提供服务,只是推理平台的起点。当模型数量、业务团队和调用量增加后,新的瓶颈通常出现在模型发布、资源分配、租户隔离和成本核算,而不再只是某一张 GPU 的利用率。平台化的目标是让模型从“手工启动的进程”变成可注册、可路由、可计量、可回滚的标准服务。
1. 多模型注册与智能路由
建议建立统一的模型注册表,至少记录模型名称、版本或 revision、量化格式、上下文上限、所需 GPU、适配的引擎、SLO 和数据合规等级。模型权重、启动参数和 Engine 应作为不可变制品管理,避免同一个模型名在不同节点实际运行不同版本。
网关或模型路由层可以根据以下维度选择后端:
| 任务类型 | 对话走通用模型,代码走代码模型,Embedding 走专用服务 | 减少错误选型和无效消耗 |
| 上下文长度 | 短请求走低延迟池,超长请求走长上下文池 | 避免长请求拖慢交互流量 |
| 服务等级 | 高优先级租户走预热副本,普通任务允许排队 | 保证不同 SLA |
| 引擎能力 | 需要结构化生成时路由到支持约束的引擎 | 避免 API 能力不匹配 |
| 发布状态 | 按租户或比例切到 canary,异常时回退 stable | 支持灰度与快速回滚 |
路由策略应避免“只看 GPU 空闲率”。更有价值的信号包括预计输入 Token、预计输出 Token、队列等待时间、KV Cache 命中率和模型加载状态。对同一模型的多个副本,可以使用最短队列、加权轮询或基于 Token 预算的调度;对不同模型,则要把质量、延迟和成本一起纳入选择。
2. 多租户隔离、配额与公平调度
多租户环境至少需要四层隔离:网络访问隔离、模型白名单隔离、并发与 Token 配额隔离、日志和数据权限隔离。不要只限制 QPS,因为一个请求可能包含很长的输入和输出;更合理的配额单位是输入 Token、输出 Token、并发请求数和 GPU 时间的组合。
可以按租户维护以下策略:
租户配额 = 每分钟请求数 + 每分钟输入 Token + 每分钟输出 Token
单请求上限 = 最大上下文 Token + 最大输出 Token + 请求体大小
并发上限 = 交互请求并发 + 流式请求并发 + 离线任务并发
调度器应支持超额拒绝、排队、降级模型和优先级继承。高优先级不能无限挤占系统资源,否则低优先级任务会形成饥饿;建议为每个租户设置最大排队时间,并在网关返回可重试的错误码。指标标签中不要直接使用任意用户 ID,否则 Prometheus 会产生高基数;租户明细可以放在日志或计费系统中。
3. 容量规划与单位 Token 成本
容量规划不能只用“GPU 利用率达到 80%”作为扩容依据。应先根据生产请求分布测出有效吞吐,再结合 SLO 反推副本数量。一个简单的估算公式是:
所需副本数 ≈ 峰值 Token 速率 ÷ 单副本在目标 P99 下的有效 Token 速率
单位 Token 成本 ≈ (GPU 小时成本 × GPU 数 × 运行小时 + 存储与网络成本)÷ 实际处理 Token 数
“有效 Token 速率”必须包含排队、失败重试、预热和低负载时段,不能直接使用压测报告中的峰值。对于 PD 分离架构,还要分别计算 Prefill 和 Decode 池的容量,避免一侧扩容后另一侧成为瓶颈。扩容触发可以组合队列等待时间、预计 Token 负载、GPU 显存水位和错误率;缩容前要等待流式请求完成,并保留足够的热副本。
成本优化通常有以下顺序:先清理无效重试和过大的 max_tokens,再优化 Prefix Cache 命中率和批处理,之后才考虑更激进的量化、低价 GPU 或跨地域调度。任何降本方案都必须同时回归准确率、P99 和故障恢复时间,不能只看云账单下降。
4. 异构 GPU、Engine 兼容与多地域容灾
不同 GPU 架构对 FP8、BF16、FlashInfer、TensorRT Engine 和显存容量的支持不同。平台应维护“模型—引擎—GPU—精度”的兼容矩阵,调度时把节点标签、驱动版本、CUDA 版本和 Engine 元数据作为硬约束。TensorRT-LLM Engine 尤其不能跨不兼容的 GPU 架构直接复用;SGLang 和 vLLM 也需要验证对应版本的 Kernel 和量化后端。
多地域部署时,可以按数据合规、网络距离和容量水位选择主区域与备用区域。跨地域只同步模型制品和配置,不应默认转发包含用户原文的请求;故障切换前要明确会话状态、Prefix Cache 和流式请求如何处理。推荐采用“区域内多副本 + 区域间冷备或热备”的分层策略,并定期演练 DNS、网关、模型仓库和密钥系统同时异常的情况。
5. 从单服务到推理平台的演进路线
可以按以下阶段推进,避免一开始就引入过多复杂组件:
| P0 单模型服务 | 固定版本、健康检查、OpenAI API、基础指标 | 能稳定发布和回滚 |
| P1 标准化服务 | 模型注册表、统一网关、配额、日志和成本标签 | 多个模型使用同一套流程 |
| P2 性能池化 | 交互/离线分池、Prefix Cache、Chunked Prefill、PD 分离 | TTFT、TPOT 和吞吐达到目标 |
| P3 平台治理 | 多地域、灾备、计费、质量评估和自动化扩缩容 | 故障可切换,成本可解释 |
每个阶段都应保留清晰的回退路径。只有当请求分布、网络条件和团队运维能力都达到要求时,才把单体服务升级为 PD 分离、远程 KV Cache 或跨地域调度;复杂度本身不是性能指标。
结语
推理引擎的工程价值在于把模型推理中的重复计算、请求调度和生成控制交给专门的 runtime 管理。真正上线时,重点不应只是启动命令,而是建立一套完整边界:SGLang、vLLM 或 TensorRT-LLM 负责高效执行,GPU 和 Kubernetes 负责资源隔离,AI Gateway 负责身份与流量治理,Prometheus/vmagent、Grafana、ELK 和夜莺负责可观测与告警;平台层再负责模型注册、路由、配额、容量和成本治理。
当团队能够同时回答“当前排队多长、首 Token 为什么慢、前缀缓存是否命中、显存还剩多少、哪个租户受到影响、如何快速回滚”时,模型才算从实验环境进入了可运营的推理平台。
网硕互联帮助中心


评论前必须登录!
注册