当前位置:首页 > 未命名 > 正文内容

vLLM 显存装不下:参数该按什么顺序调

xiaorui6小时前未命名1

vLLM 部署最常见的崩溃场景不是模型跑得慢,是启动时或跑着跑着 OOM。这篇不讲原理,只讲参数该按什么顺序调、每个参数动下去代价是什么。

验证截至 2026-10-21。依据 vLLM 官方文档(Conserving Memory / Optimization / FP8 三章),并与公开技术分析交叉核对;括号内标注了确认时点的数值,请以你所运行版本的官方文档为准。

环境与版本

  • 适用对象:vLLM 的 vllm serve 与 LLM 两类接口,单卡到多机多卡均适用
  • 版本敏感项:gpu_memory_utilization 的默认值在历史上变过,下文标注的 0.92 是 2026-08 在文档与 CacheConfig 源码中确认的值,旧教程里常见的另一个数字已经不适用
  • 硬件相关:量化那一节的收益严格依赖显卡计算能力,见下文边界部分

先说结论:一次只改一个参数

调参最常见的失败不是选错了值,而是同时改了五六个值,最后既不知道哪个起作用,也没法回滚。

推荐的固定顺序是四步:

1. 先让模型装进显存

2. 再把长度上限对齐真实负载

3. 然后给 KV cache 留出余量

4. 最后才动 batch 和延迟

前三步没定下来就去调 batching 相关的参数,通常什么也不会发生——因为限制根本不在那儿。

第一步:gpu_memory_utilization 是第一个该动的值

官方定义:模型执行器可使用的显存比例,取值 0 到 1,默认 0.92。

它的机制决定了它为什么排第一:vLLM 先按这个比例把显存整块划走,扣掉模型权重和运行时开销之后,剩下的全部给 KV cache。所以调高它,KV cache 立刻变大,能同时接住更长和更多的请求。

但不要往 1 推,有两个理由:

  • 它按整张卡计算。 卡上还跑着别的进程时(Kubernetes 里共享 GPU 是常态),这个比例算出来就是错的。
  • 实际占用会比计算值高一截,来自显存碎片和瞬时激活张量。把余量压成 0 的典型后果是"大部分时候一切正常,某些请求组合下突然炸掉"。

一个有用的判据:如果调高它吞吐没有涨,说明瓶颈不在显存,卡住你的是 max_num_seqs 或 max_num_batched_tokens,继续拧这个旋钮没有意义。

第二步:长度上限和并发上限,直接对应 KV cache 的两个乘数

参数作用降下去的代价
max_model_len单条序列的最大 token 数长文本会被截断或拒绝
max_num_seqs一批里的并发请求上限并发上不去,请求开始排队
max_num_batched_tokens单批最大 token 数,影响 prefill 与 decode 的平衡官方提到大于 8192 有利于吞吐,压太低会牺牲吞吐

KV cache 的需求大致就是"序列长度 × 并发数"的函数,所以装不下的时候不是玄学——降这两个值,需求按比例下来。选降哪个取决于你的负载:长文本为主就压并发上限,高并发短请求为主就压长度上限。

第三步:TP 是容量选项,不是性能选项

这是最普遍的一个误解。官方文档的判据很直接:

  • 单卡放不下、单机多卡放得下 → 用 tensor parallelism
  • 单机都放不下 → TP 加 PP(流水线并行)
  • 取值:tensor_parallel_size = 每节点 GPU 数,pipeline_parallel_size = 节点数。文档给的例子是 2 节点 × 8 卡 → TP=8、PP=2
  • 例外:单节点内 GPU 无法均分时,可以设 TP=1、PP=GPU 数,让模型层做不均分切分

tensor_parallel_size 的默认值是 1。也就是说什么都不设,引擎就只用一张卡,哪怕机器上插了八张。多卡机器性能不及预期,第一个该查的就是这个值。

模型本来就能塞进一张卡时开 TP 会怎样:每张卡分到自己的 KV cache,总容量确实变大——这部分是真实收益;但每一层都多了卡间通信,而且是同步的。所以这不能算无条件的赢,得实测过再定。

官方给出的 OOM 缓解顺序

按顺序试,不要跳步,因为越往后代价越大:

1. 提高 gpu_memory_utilization(代价:留给别人的显存变少)

2. 降低 max_num_seqs 或 max_num_batched_tokens(代价:并发或吞吐下降)

3. 提高 tensor_parallel_size(代价:同步开销)

4. 提高 pipeline_parallel_size(代价:延迟)

另外有个容易被忽略的参数:kv_cache_memory 可以直接指定 KV cache 大小,跳过启动时的显存 profiling 阶段。profiling 结果不稳定、或者启动耗时太长时,这是个绕过去的办法。

量化这笔账要按硬件算

官方 FP8 文档的说法是:显存减半,吞吐最高提升 1.6 倍,精度影响很小。两个前提容易被跳过:

一是硬件门槛。 FP8 计算需要 NVIDIA 计算能力 ≥ 8.9(Ada Lovelace / Hopper / Blackwell)。Turing / Ampere 上会退化成仅权重的 W8A16,走 Marlin kernel——显存收益还在,但拿不到完整的 W8A8 加速。

二是 kernel 选择。 vLLM 在加载时自动挑 FP8 GEMM kernel,启动日志里会打一行 Selected。如果推理挂住且不报错,官方建议试 VLLM_USE_DEEP_GEMM=0 或 --linear-backend cutlass。注意 --linear-backend 只作用于量化线性层,MoE 专家走的是单独的 --moe-backend,别设错了以为生效了。

FP8 有两种表示,E4M3(范围小、精度高)和 E5M2(范围大、精度低),权重和激活的实际取值分布决定该用哪个。

边界与坑

  • 显存要按权重 + KV cache + 余量三块估,只算权重就会在"看起来够"的情况下 OOM
  • 所有参数都与版本绑定。跨版本升级后必须重查文档,尤其是配置项重命名这类破坏性变更
  • 共享 GPU 场景下 gpu_memory_utilization 的语义会失真,此时不如直接用 kv_cache_memory 锁死
  • 调参期间一次只改一个值,否则无法归因

常见问题

Q:gpu_memory_utilization 是不是越高越好?

不是。它按整卡计算,共享 GPU 时会算错;且不留余量会在特定请求组合下突然 OOM。调到吞吐不再随它增长就够了。

Q:多卡机器性能上不去,先查什么?

tensor_parallel_size,它默认是 1。

Q:模型装得下,还有必要开 TP 吗?

KV cache 总量变大是真的收益,但每层多了同步通信。要测,不要默认开。

Q:量化一定能解决显存问题吗?

显存层面基本能,加速层面看硬件——计算能力低于 8.9 的卡拿不到完整 FP8。

参考与延伸

  • vLLM 官方文档:Conserving Memory、Optimization、FP8 三章(docs.vllm.ai,请以所运行版本为准)
  • 交叉核对:TT Lab Blog《Inside vLLM (7) — Deployment Tuning, Common Pitfalls, and OOM Triage》,2026-08-12,该文明确声明其数值核对至该日期
  • 显存估算方法:权重 / KV cache / 余量三块拆分法,可与上述参数一一对应