vLLM在生产环境高并发推理时出现CUDA OOM,先不要急着调小batch,因为OOM可能来自KV cache预分配、长prompt瞬时峰值或显存碎片,不同原因对应的调整参数完全不同。建议先定位OOM出现的阶段,再决定改哪一类batch策略。
CUDA OOM排查重点在“瞬时还是稳态”:瞬时OOM多半由并发突发或长prompt触发,优先限制max_num_seqs和请求排队;稳态OOM则要调低gpu_memory_utilization或启用chunked prefill。调整后须用同等峰值流量验证吞吐和延迟,不能只看显存曲线。
先定位OOM来自哪个阶段
观察vLLM日志和OOM发生时机。如果请求一进来、还在prefill阶段就OOM,很可能是一次性处理了超长prompt或大量prompt;如果是在decode阶段逐渐涨满,多半是KV cache累计超过上限。用nvidia-smi `--query-gpu`=timestamp,memory.used,utilization.gpu `--format`=csv -l 1定时记录显存曲线,能区分是瞬时尖峰还是持续走高。也可以看vLLM启动时打印的KV cache分配量,比如Maximum concurrency for ...,这能直接告诉你当前显存能撑住多大的batch。
如果进程启动阶段就OOM,通常不是batch问题,而是`--gpu-memory-utilization`设置过高,给CUDA context和模型权重留下的空间不足;这种情况先调低gpu_memory_utilization,再处理batch。
调整vLLM的batch与显存参数
vLLM的batch行为主要受`--max-num-seqs`、`--max-model-len`和`--enable-chunked-prefill`影响。一个可用的启动参数示例(数值需按实际显存调整):
python -m vllm.entrypoints.openai.api_server \
`--model` /path/to/model \
`--max-num-seqs` 64 \
`--max-model-len` 8192 \
`--gpu-memory-utilization` 0.85 \
`--enable-chunked-prefill``--max-num-seqs`是并发序列上限,也是动态KV cache的上限之一。把它从默认值调低,是压住OOM最直接的手段;但调太低会导致高并发时大量请求排队,响应时间变长。`--max-model-len`限制单条序列最大长度,如果业务里偶尔有超长文本,可以按实际分布设置,而不是直接给满支持长度。`--enable-chunked-prefill`会把长prefill拆成小段,让显存使用更平滑,但会增加调度开销,需要结合请求长度分布决定是否开启。
使用`--tensor-parallel`时,KV cache按GPU数均分,OOM发生在单卡上就要按单卡显存校核这些参数,不要只看整体容量。
在上游控制并发与排队
即使vLLM内部会排队,过大的瞬时并发也会让排队请求积压,进而延长请求持有时间,让显存压力更久。建议在API入口处增加并发限制,让进入vLLM推理引擎的请求速率更平稳。比如接入层用信号量限制同时进行的推理请求数:
import asyncio
sem = asyncio.Semaphore(64)
async def call_vllm(payload):
async with sem:
async with httpx.AsyncClient() as client:
return await client.post("http://127.0.0.1:8000/v1/completions", json=payload)这里的并发数要低于vLLM的`--max-num-seqs`,留出余量,避免请求在vLLM队列中堆积。也可以单独设置排队超时,超过就直接返回错误,避免用户反复重试放大压力。
验证调整是否有效
- 启动后观察日志中KV cache分配量和模型加载是否正常,确认没有启动期OOM。
- 用与生产峰值接近的流量回放或压测,看OOM是否再现;记录显存曲线、吞吐和延迟。
- 如果OOM只在长时间运行后出现,重启后恢复,优先怀疑显存碎片;可尝试设置
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True后再观察。 - 调整batch后若延迟下降但吞吐明显偏低,说明并发限制过严,需要按业务SLA重新调节max-num-seqs和上游并发。
不要单独看显存占用率,还要看稳定性:如果启动时显存占用很低,但请求高峰期瞬间打满,说明batch峰值管理仍需加强;如果启动后占用一直很高且无OOM,说明现有参数刚好卡在边界,需保留一定余量应对波动。