欢迎光临

vLLM 显存不足怎么查?权重加载、KV Cache 与并发排障

vLLM 报显存不足时,先看服务走到了哪一步。权重加载失败、KV Cache 无法容纳配置的上下文,以及服务启动后在高并发下抢占或 OOM,对应的调法不同。先记录第一条异常和它前面约 30 行日志,每次只改一个影响显存的参数。

NVIDIA GeForce RTX 2080 Ti 硬件实拍资料照片
NVIDIA GeForce RTX 2080 Ti 硬件实拍资料照片,Fritzchens Fritz 摄于 2018-11-12。本站生成缩放或裁切缩略图。 原始照片 · CC0 1.0

用日志区分三个阶段

现象 先查什么 优先处理
权重加载期间报 CUDA OOM 空闲显存、其他进程、实际权重精度、模型加载峰值 换空闲卡、减小模型或用后端支持的量化权重
权重已加载,KV Cache 初始化报错 可用缓存块、最大上下文、CUDA Graph 和工作区开销 先按业务需要降低 –max-model-len,保留真实显存余量
空载能启动,并发时延迟飙升或失败 请求实际 token 数、运行中和排队请求、抢占、KV Cache 占用、第一条异常 限制请求长度或并发,分级压测;再单独调整批处理预算

还有一种报错出现在权重加载之前:启动时可用显存低于配置所需的预算。此时先看同卡其他进程,或把 –gpu-memory-utilization 调到这张卡实际能承担的范围。保留调参前后的 nvidia-smi 输出。

本次测试就遇到了这一层检查。RTX 2080 Ti 总显存为 11.0 GiB,当时空闲 9.87 GiB。vLLM 0.32.0 的默认比例为 0.92,需要约 10.12 GiB,服务在加载权重前就退出。显式设置 0.35 后才进入后续的模型与缓存测试。这里的比例只适用于本次小模型实验。

1
2
nvidia-smi --query-gpu=index,name,memory.total,memory.used,memory.free --format=csv
nvidia-smi --query-compute-apps=pid,process_name,used_gpu_memory --format=csv

权重装不下时,先估权重和加载峰值

以十进制 7B 参数、每参数 2 字节为例,裸 FP16 权重约 14 GB(约 13.0 GiB)。还要加上 CUDA 上下文、运行时张量、工作区和缓存。量化权重也会附带分组尺度等数据,并依赖 GPU 和内核支持。多卡张量并行会分摊部分内存,同时引入通信开销,按当前模型和后端核对分片布局。

如果报错栈落在权重加载,缩短上下文不会缩小那批权重。先用小模型验证服务能启动,再选择合适的权重精度、模型大小或设备。核对真实可用显存,避免把宿主机上看不到的容器进程或其他用户任务漏掉。

权重已装下时,看 KV Cache 能容纳多少 token

对普通 decoder-only Transformer 的全注意力层,一个 token 的 KV Cache 粗算为 2 × 层数 × KV heads × head_dim × 每元素字节数。例如 32 层、8 个 KV heads、head_dim 128、FP16 时约 128 KiB/token,一条 8,192 token 的序列约 1 GiB。估算应计入输入和生成;GQA 用 KV heads,混合注意力、滑动窗口、MLA、分块及多卡布局则以实际实现为准。

–max-model-len 限制单条序列的总长度;–gpu-memory-utilization 是执行器的显存预算比例。降低前者可以让较小的缓存池通过上下文容量检查,但缓存池通常仍按预算分配。使用自动分配时,提高预算比例可增加缓存,也会减少显存余量。若安装版本支持 –kv-cache-memory-bytes,它可直接指定每 GPU 的 KV Cache 字节预算,覆盖自动缓存大小估算;启动时的可用显存检查仍可能使用比例预算。

单卡复现:用同一个模型分离缓存容量与请求行为

实测环境是 WSL2、RTX 2080 Ti(11 GiB)、vLLM 0.32.0、PyTorch 2.13.0+cu130。使用同一版 Qwen2.5-0.5B-Instruct、FP16 和 16 MiB 的显式 KV Cache 预算,两个配置都成功加载权重,日志记录的加载显存都是 0.93 GiB。

  • –max-model-len 512:启动成功,日志报告缓存池容量 1,360 token,/v1/completions 返回 HTTP 200。
  • –max-model-len 2048:权重加载后在容量检查时报错,日志估算可接受的最大序列长度为 1,344。缓存池总 token 和启动检查估计值是两个日志字段,部署时以该版本校验结果为准。错误将 GiB 四舍五入,两个数字即使显示相同,也应看完整错误和估算长度。
vLLM 单卡测试终端输出
vLLM 单卡测试终端输出。截取实际运行日志。

这组测试覆盖了启动预算检查、模型加载、缓存容量校验和一次请求。下面的并发步骤供读者在自己的请求分布上验证。

下面的命令固定公开模型 revision,服务只监听本机。显式设置 16 MiB 缓存,是为了在同一张卡上复现容量边界。对照时先停止第一个进程,只把 –max-model-len 改成 2048,再启动一次。部署时按业务上下文和硬件重新选预算与后端。

1
2
3
4
5
6
7
8
9
MODEL=Qwen/Qwen2.5-0.5B-Instruct
REV=7ae557604adf67be50417f59c2c2f167def9a775

vllm serve "$MODEL" --revision "$REV" --dtype half --enforce-eager \
  --host 127.0.0.1 --port 18737 --max-num-seqs 1 \
  --enable-chunked-prefill --max-num-batched-tokens 512 \
  --block-size 16 --kv-cache-memory-bytes 16777216 \
  --attention-backend TRITON_ATTN \
  --max-model-len 512 --gpu-memory-utilization 0.35

打开另一个终端,发一个固定请求。记录 HTTP 结果、启动日志中的权重显存和缓存容量。测试较长上下文时保留同一模型、精度和后端,以日志是否通过容量校验为判断依据。

1
2
3
curl -fsS http://127.0.0.1:18737/v1/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"Qwen/Qwen2.5-0.5B-Instruct","prompt":"1+1=","max_tokens":4,"temperature":0}'

只有并发起来才出问题时,固定请求长度做阶梯测试

  1. 选一组脱敏输入,记录 tokenizer 计数和输出上限。从单个请求开始,固定模型、后端和输入长度。
  2. 在测试实例逐步增加客户端并发。每一级同时看成功率、P95 首 token 延迟、排队、缓存占用和抢占。服务刚起来就出错,先回到启动日志。
  3. 用 curl -fsS http://127.0.0.1:18737/metrics 查看当前版本实际暴露的指标。抢占增加同时延迟变差时,先降低并发或缩短请求,再检查 KV Cache 预算。–max-num-seqs 限制调度序列数量,–max-num-batched-tokens 限制每次调度处理的 token 数,分别改变才能知道哪项生效。
  4. 如果请求在 API 层因总长度被拒绝,先计算模板和生成预算。如果出现真正的 CUDA OOM,保留最早堆栈,核对同卡进程、运行时峰值和失败时的批次大小。

选型阶段可回看SGLang 和 vLLM 的对比。正式压测时固定输入、输出和并发,再比较不同预算下的延迟与吞吐。

参考资料:vLLM 显存配置、vLLM serve 参数、vLLM 监控指标。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » vLLM 显存不足怎么查?权重加载、KV Cache 与并发排障
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址