vLLM 性能问题排查记录:从 Docker 启动失败到发现 CUDA 兼容层的坑
目录
今天花了几个小时排查一个 vLLM 的性能问题,过程中踩了不少坑,记录一下。
🎯 起因:GitHub Issue #35048
有用户反馈 vLLM 从 v0.14.0 升级到 v0.15.1 后,MiniMax-M2.5 模型的推理性能出现了明显退化:
- Per-request 吞吐量下降约 19%
- 延迟中位数增加约 24%
- TTFT p95 几乎翻倍
作为 vLLM 的开发者,决定在本地复现一下这个问题。
🔧 环境准备
手上只有一张 RTX 3090(24GB),先拉两个版本的 Docker 镜像:
docker pull vllm/vllm-openai:v0.14.0
docker pull vllm/vllm-openai:v0.15.1
MiniMax-M2.5 需要 220GB 显存,跑不起来。换成本地有的 Qwen2-7B-Instruct 来测试。
💥 第一个坑:v0.15.1 启动失败
v0.14.0 启动正常,但 v0.15.1 直接报错退出:
RuntimeError: Unexpected error from cudaGetDeviceCount().
Did you run some cuda functions before calling NumCudaDevices()
that might have already set an error?
Error 803: system has unsupported display driver / cuda driver combination
奇怪的是,两个镜像用的是 同一个 PyTorch 版本(2.9.1+cu129),为什么一个能跑一个不能?
🔍 排查过程
1. 直接用 ctypes 调用 CUDA Runtime
import ctypes
cudart = ctypes.CDLL('libcudart.so')
cudart.cudaGetLastError.restype = ctypes.c_int
print(f'cudaGetLastError: {cudart.cudaGetLastError()}')
结果:
- v0.14.0:
cudaGetLastError: 0✅ - v0.15.1:
cudaGetLastError: 803❌
还没调用任何 CUDA 函数,错误就已经存在了!说明 libcudart.so 加载时的初始化代码就出错了。
2. 检查 libcudart.so 文件
两个镜像的 libcudart.so.12.9.79 文件 MD5 完全相同,不是库文件本身的问题。
3. 检查 ldconfig 解析路径
ldconfig -p | grep libcuda
v0.14.0:
libcuda.so.1 => /lib/x86_64-linux-gnu/libcuda.so.1
v0.15.1:
libcuda.so.1 => /usr/local/cuda-12.9/compat/libcuda.so.1 # ← 问题在这!
libcuda.so.1 => /lib/x86_64-linux-gnu/libcuda.so.1
🎯 根因定位
v0.15.1 镜像的 ldconfig 配置变了,导致 libcuda.so 优先从容器内的 CUDA 兼容层加载(版本 575.57.08),而不是宿主机驱动(版本 580.126.09)。
CUDA Runtime(libcudart)初始化时会调用 Driver API(libcuda),575 的 libcuda 和 580 的内核驱动不兼容,所以报错 803。
这解释了为什么:
- nvidia-smi 能正常显示 GPU 信息(走的是宿主机驱动)
- 但 PyTorch CUDA 初始化失败(走的是容器内兼容层)
✅ 解决方案
设置 LD_LIBRARY_PATH 让宿主机的 libcuda 优先:
docker run --gpus all \
-e LD_LIBRARY_PATH=/lib/x86_64-linux-gnu:/usr/local/nvidia/lib64:/usr/local/cuda/lib64 \
vllm/vllm-openai:v0.15.1 \
...
问题解决,v0.15.1 正常启动了!
📊 性能对比结果
在 Qwen2-7B-Instruct(非 MLA 模型)上对比:
| 版本 | Per-request tok/s |
|---|---|
| v0.14.0 | 49.69 |
| v0.15.1 | 49.55 |
差异 <1%,几乎没有性能退化。
这说明 issue 中报告的性能问题 大概率是 MLA attention 相关的,而不是通用推理路径的问题。
📝 代码变更分析
v0.14.0 → v0.15.1 共 371 个 commits,其中 MLA 相关变更 13 个:
[MLA] Fuse cat and quant for fp8 kv-cache (#32950)[FlashMLA] Update FlashMLA to expose new arguments (#32810)[Model Runner V2] Support FLASHINFER_MLA backend (#32709)- MLA backend 选择逻辑变更
attention 和 MLA 路径大量重构(44 文件,+2080/-1170 行),性能退化可能出在这些改动中。
🤔 遗憾
限于设备(只有单卡 3090),没法跑 MiniMax-M2.5 或 DeepSeek-V2 这类 MLA 模型来完全复现问题。已经把排查结果回复到 issue 上了,希望有 H100/H200 资源的同学能继续 bisect。
💡 经验总结
-
Docker 镜像升级后启动失败:不一定是代码问题,可能是 ldconfig 配置变化导致加载了错误版本的系统库
-
CUDA 兼容层是把双刃剑:它让老版本 CUDA 能跑在新驱动上,但如果配置不当也会导致版本不匹配
-
排查 CUDA 问题的技巧:
- 用
ctypes直接调用cudaGetLastError看有没有残留错误 - 用
ldconfig -p | grep cuda检查库解析路径 - 对比
/proc/self/maps看实际加载了哪个版本的库
- 用
-
性能对比要控制变量:非 MLA 模型测不出 MLA 相关的性能退化,要复现问题得用对应的模型架构
排查问题虽然花了不少时间,但学到了很多 CUDA 底层的知识,值了。