最近在折腾本地部署Qwen2.5 7B(int4量化版),用的vllm框架,服务器是两张RTX 4090(24G),设置了max_num_seqs=64和gpu_memory_utilization=0.9。刚开始跑几个请求还挺正常,但连续处理几十个prompt之后,显存就慢慢涨到46G然后直接OOM了。查了vllm的文档说是有动态显存管理的,但感觉没生效。我试过调低max_num_batched_tokens到2048,也没用。是不是我哪里设置不对?还是7B模型本身在长文本多并发下就是容易爆显存?求大佬们指点一下排查思路或者有没有其他轻量部署方案推荐。
用vllm部署Qwen2.5 7B,显存一直涨到OOM,是代码有问题吗?
全部回复
共 159 条说实话你这个配置和参数我看了下,感觉问题大概率出在gpu_memory_utilization=0.9这个值上。vllm虽然号称动态管理,但0.9意味着它一开始就会预留90%的显存给KV cache,两张卡加起来43.2G,剩下那点空间跑7B模型(int4约4-5G)加上中间激活值很容易就顶到极限了。建议先把这个值降到0.7左右试试,给模型本身留足余量。另外max_num_seqs=64对于7B模型有点激进了,你可以先降到32,看显存曲线会不会平稳下来。还有个小细节,vllm的prefill阶段会一次性申请完整序列长度的显存,如果你的prompt长度差异很大,长序列会吃掉大量临时显存,可以在启动时加个--enforce-eager参数,强制用更保守的调度策略。如果调了这些还不行,不妨试试基于llama.cpp的部署方案,它对连续式显存管理更扎实,尤其是量化模型。不过我好奇的是你用的啥数据集做压力测试?如果全是超长上下文的话,光KV cache就能吃掉接近20G,那确实得降并发数。
感觉像是vllm的预分配机制和量化模型的显存回收没配合好,int4虽然省显存但碎片化可能更严重。建议试试把gpu_memory_utilization降到0.8,然后max_num_seqs先砍到32看看能不能跑稳。另外检查下是不是prompt长度差异太大,vllm对变长序列的缓存管理有时候会抽风。如果还不行的话,可以试试用awq量化配合exllamav2,那个对4090的双卡支持更稳一点。
这问题我也遇到过,vllm那个动态显存管理其实挺迷的,对量化模型的释放策略好像不太稳定。建议你把gpu_memory_utilization改低到0.8试试,或者手动限制一下max_model_len到4096,有时候是长序列预分配吞了显存不吐出来。另外如果并发没那么高,可以试试换llama.cpp或者sglang,对显存控制更稳当。
试试把gpu_memory_utilization降到0.8,然后检查下是不是有请求没正确释放上下文。
试试把gpu_memory_utilization调到0.85,max_num_seqs降到32,vllm的显存回收确实有时会滞后。
显存慢慢涨到OOM感觉像是内存泄漏,vllm的动态管理对长上下文连续请求确实有时不太灵敏。你试试把gpu_memory_utilization降到0.8或者0.85,留点余量给KV cache的峰值波动。另外检查下是不是启用了--enable-prefix-caching,这个选项打开后如果前缀不重复反而会多吃显存。如果还不行,可以切到llama.cpp的server模式,那个对量化模型的显存控制更稳当,虽然吞吐低点但胜在不崩。
看着不像代码问题,vllm的paged attention主要管KV cache,但int4量化后权重本身不占多少,你设0.9利用率加上双卡,理论上有40G+可用,显存还涨的话大概率是某些长prompt的中间激活值没被及时释放。建议先开vllm的日志看看有没有显存碎片警告,或者把max_num_seqs降到32试试,有时候并发太高会让预分配缓冲区膨胀。另外可以试试把模型换成AWQ或者GPTQ的4bit版本,有时候不同量化格式对显存管理影响挺大的。
说实话我怀疑不是vllm的问题,int4量化版7B本身占显存就比理论值高不少,加上两条4090是分开的显存池,跨卡通信也会吃掉一部分。你试试把gpu_memory_utilization降到0.7,然后max_num_seqs调成16跑一轮看看涨幅曲线,如果还是线性涨可能是paged attention的缓存没释放干净,可以看看是不是某个版本的bug,我上次用0.4.2也遇到类似情况,换个版本就好了。
另外你确认下是不是长文本场景下prefill阶段把显存峰值抬上去了,vllm的动态管理主要管KV cache,但量化模型在decode时会有额外的临时buffer。我自己的经验是直接换llama.cpp部署,虽然吞吐低点但显存控制稳很多,7B int4跑满24G单卡完全够。
你这情况我跑7B也遇到过,vllm那个显存管理对int4量化支持其实有点糙,动态回收不太跟手。可以先试试把gpu_memory_utilization降到0.8,再关掉prefix caching,很多时候是缓存占着不释放。另外max_num_seqs调到32试试,64在双卡上反而容易触发碎片化分配。要是还不行,换llama.cpp的server跑int4,显存占用稳定得多,就是吞吐低点。
显存涨到OOM大概率不是代码问题,vllm的显存管理对int4支持不太好,建议换sglang试试。
显存碎片化了吧,试试把gpu_memory_utilization降到0.85再加个--enable-chunked-prefill看看。
你这像是vllm的KV cache没及时释放,升级到最新版或者换swift部署试试看。
检查下是不是vllm版本太老,升到0.6.3+并开enable_prefix_caching试试,能省不少显存。
可能是连续请求的kv cache没及时释放,试着把max_num_seqs降到32,顺便看下nvidia-smi里是不是有其他进程占着显存。
试试把gpu_memory_utilization调低到0.7,留点显存给碎片和缓存,vllm对量化模型的内存估算有时不准。
之前跑Qwen2.5 7B也遇到过类似情况,后来发现是vllm的preemption和KV cache管理在长上下文下会持续占用显存,尤其是多并发时更明显。你试试把gpu_memory_utilization降到0.8,同时加个--enforce-eager参数关掉CUDA graph,能省不少显存。另外,int4量化用AWQ或GPTQ格式,别用gguf,vllm对后者支持不太好。如果还不行,可以考虑换SGLang,它对动态显存控制更激进,我这边跑同量级模型稳定很多。
我猜大概率不是代码问题,vllm的动态显存管理主要是针对KV cache的预分配和释放,但你这种情况更像是Python侧或者CUDA context本身有碎片化累积。我之前遇到过类似情况,最后发现是vllm的preemption机制在长序列场景下会反复把某些block换出换入,导致显存碎片越攒越多,最后触发OOM。你可以试试显存利用率调到0.8以下,给CUDA留点余量,另外检查一下是不是prompt里带了超长system prompt,Qwen对长上下文的显存消耗是超线性的。还有个思路是换用AWQ或者GPTQ的4bit版本,比int4的显存占用更稳定,或者干脆用llama.cpp的server模式跑,虽然吞吐低点但内存控制更可控。最后建议你开一下vllm的日志级别到debug,看OOM前有没有具体的block管理警告,那个信息比文档有用多了。
我之前也踩过这个坑,vllm的显存增长不一定是代码问题,大概率是prefill阶段把KV cache撑爆了,尤其多并发长文本时。你可以试试把gpu_memory_utilization降到0.8,同时强制限制max_model_len到4096,有时候默认的模型最大长度会吃满缓存。另外检查下是不是vllm版本太老,老版本动态回收有bug,升到最新版或者换0.6.x分支能解决。如果还不行,干脆换llama.cpp跑gguf,7B int4在4090上单卡轻松带20K上下文,部署还简单。
同款配置踩过这坑,vllm的显存管理对int4模型支持有时确实有bug,建议先试试把gpu_memory_utilization降到0.8,同时换用最新版vllm看下,老版本对量化模型的内存回收有问题。另外长文本场景下max_num_seqs=64有点激进,改成32配合--enforce-eager模式能缓解不少。我之前用AWQ量化版Qwen2.5 7B,连续跑500个请求也没爆,你可以对比下是不是GPTQ和vllm的兼容性问题。实在不行就换sglang或者exllamav2,部署成本差不多但显存控制稳很多。
跑长文本试试把--enable-prefix-caching打开,另外max_num_seqs调小到16,你这配置明显是显存碎片化炸的。
之前也踩过这坑,换awq量化加投机采样能压一半显存,4090别开0.9,留2G给CUDA context。
说实话你这个问题我上周刚踩过坑,vllm那个动态显存管理不是完全自动的,它只对paged attention的KV cache生效,但int4量化后的权重和激活值还是会残留在显存里。你max_num_seqs设64有点太激进了,7B模型即使int4,每个seq的KV cache也要按最大上下文长度预分配,你连续请求如果长度波动大,预分配的内存根本释放不掉。我建议你先用nvidia-smi盯着看是不是逐步递增,如果是阶梯式上涨,那大概率是vllm的预分配块没回收,试试把--max-model-len设成4096或者更小,别用默认的32768。另外你gpu_memory_utilization=0.9其实有点危险,两张卡共享显存的话,vllm不会自动做负载均衡,单卡可能已经爆了另一张还空闲,改成0.7左右给系统留点余量。还有个歪招,用--enforce-eager模式关掉CUDA graph,虽然速度慢点但显存占用能降15%左右。实在不行就换llama.cpp的server模式,虽然吞吐低,但显存管理是硬上限,绝对不会OOM。
我之前也踩过类似的坑,vllm那个动态显存管理其实跟你的gpu_memory_utilization设置有很大关系,0.9看似留了10%余量,但加上CUDA context和KV cache的碎片化,实际可用空间比你想的小很多。你试试把gpu_memory_utilization降到0.8,同时把max_num_seqs调成32,看看峰值会不会降下来。另外你用的是int4量化版,但vllm对AWQ或GPTQ的支持有时候会额外保留未量化的权重做reference,显存开销比预想高不少,建议确认下是不是加载了多个副本。长文本多并发确实容易爆,7B模型在4090上单卡跑2K上下文还好,但64个seq同时跑,每个都带长history的话,KV cache膨胀速度是超线性的。我之前还试过把--enable-prefix-caching打开,对重复前缀的请求能省不少显存,你可以加上看看。如果还是不行,建议换用llama.cpp的server模式,虽然吞吐低点,但显存控制稳定多了,至少不会让你半夜起来看OOM。排查的话,你可以用nvidia-smi dmon实时盯显存曲线,看是哪个阶段涨上去的,是prefill还是decode,这样能更精准定位问题。