用的两张4090,vLLM 0.6.3,Qwen2.5-7B-Instruct,max_model_len设的8192,QPS压到20左右就开始报KV cache不够,但nvidia-smi看显存明明还剩8G多。怀疑是预填充和decode阶段显存分配打架,试过调--gpu-memory-utilization从0.9降到0.8,反而更慢了。另外,用OpenAI兼容接口接LangChain时,第一个请求总是特别慢,后续才正常,是不是warmup没做对?有没有大佬指点一下,这种场景下是应该开chunked prefill还是手动调一下调度策略?或者干脆换TensorRT-LLM?先谢过各位了。
vLLM部署Qwen2.5-7B遇到显存碎片化,吞吐上不去怎么调?
全部回复
共 54 条这情况我之前用A100也踩过,显存剩不少但KV cache报错多半是碎片化没跑了。建议先把--max-num-seqs调小试试,比如64或32,限制并发能缓解预填充和decode抢资源。chunked prefill可以开,但注意要配合--enable-chunked-prefill和--max-num-batched-tokens一起调,不然效果不明显。第一个请求慢正常,vLLM默认lazy加载,可以加--enforce-eager或者提前发个空请求预热,不过后者更实用。TensorRT-LLM没必要换,调参空间还很大。
这问题我上周刚踩过一模一样的坑,vLLM这版本对Qwen的显存预留策略特别激进,你看到还剩8G其实是被预分配给了paged attention的block池,但池子碎片化导致实际可用KV block不够。建议先把--max-num-seqs降到64以下,然后开--enable-chunked-prefill,配合--preemption-mode swap,别用recommend的recompute,能明显缓解碎片。不过chunked prefill会和你的QPS冲突,因为预填充被切碎后调度开销反而变大,所以也别急着开,先看看是不是max_model_len虚高导致block table膨胀,把长度砍到4096试试,很多场景下根本用不满8K。至于首请求慢,大概率是CUDA graph捕获和tokenizer初始化叠加了,你可以试着预热一个20token的空请求再进LangChain,或者干脆用vLLM原生的AsyncLLMEngine自己写个调度,别走OpenAI兼容层,那个在并发低时确实有额外延迟。最后说下TensorRT-LLM,除非你愿意花两天调图优化,否则这个场景下收益真不如把vLLM升到0.8.x,新版对KV cache的合并策略改了不少,我升级后碎片问题直接少了三分之一。
遇到过类似的,KV cache报错但显存剩不少,多半是碎片化,vLLM的page管理在长上下文下确实容易这样。建议先把max_model_len降到4096试试,QPS压力不变,看吞吐有没有改善,另外开一下--enable-chunked-prefill,对混合负载友好很多。第一个请求慢那个,大概率是CUDA graph和采样器初始化的问题,可以在启动后发个空请求预热一下,或者检查下--enforce-eager是不是被隐式关了。换TRT-LLM的话性能上限更高,但调参成本也大,先试软件层优化吧。
试试把max_model_len砍到4096,chunked prefill开起来,应该能救回来。
开chunked prefill试试,你这八成是预填充占块太多,0.8显存利用率反而加剧了碎片化。
第一个请求慢正常,把warmup请求也走一遍LangChain再压测。
遇到过类似的,vLLM老版本对chunked prefill支持不好,建议升到0.6.6+再开,显存碎片能缓解不少。
这事儿我之前也踩过坑,vLLM 0.6.x的KV cache管理确实有点呆,尤其长上下文场景下碎片化挺明显的。你把max_model_len砍到4096试试,吞吐能涨不少,前提是你的业务不要求那么长输入。chunked prefill值得开,但别用默认参数,配合--enable-chunked-prefill和--max-num-batched-tokens一起调,效果会好很多。至于warmup慢,那是vLLM在预分配显存做profile,正常现象,可以加个--enforce-eager省掉这步,代价是首token延迟会高一点。
开chunked prefill吧,你这情况显存碎片基本就是预填和解码抢资源,0.8反而更慢是因为缓存更紧了。
显存剩8G但KV cache报不够,大概率是碎片化没跑了,vLLM 0.6.3的paged attention在连续请求下确实容易这样。建议先开chunked prefill试试,能显著缓解预填充和decode的显存争抢,另外把--max-num-batched-tokens调低点比如4096,给decode留更多余量。第一个请求慢是正常的,因为要跑CUDA kernel的warmup,你可以发个假请求预热一下再对外提供服务。TensorRT-LLM没必要换,这场景vLLM调调参数就够用了,重点看下是不是max_num_seqs没设对。
显存剩8G但报KV cache不够,大概率是显存碎片化加预留给CUDA context的部分没释放,你试试把--max-num-seqs调小点比如256,同时开--enable-chunked-prefill,这俩组合对7B模型挺管用的。另外第一个请求慢是正常的,vLLM要跑一次CUDA graph捕获,你可以用--enforce-eager关掉试试,但代价是单token延迟会高些。TensorRT-LLM没必要换,先调参再说。
显存剩8G但KV cache报不够,大概率是预填充和decode的显存池没打通,vLLM 0.6.3这个版本对连续请求的块管理确实有点呆。chunked prefill值得开,但记得把--max-num-batched-tokens调大点,不然prefill占着块不放,decode照样饿死。另外首请求慢多半是paged attention的显存映射没初始化,预热时多发几个不同长度的假请求把块表填起来就行,别光发一个。TensorRT-LLM在这场景提升有限,除非你QPS要上100,否则先把vLLM调明白更划算。
显存剩8G但KV cache报错,八成是碎片化没跑,试试开chunked prefill配合--num-engine-steps拉长调度窗口。
这问题我上周刚踩过,八成是prefix-cache没开,LangChain那边每次请求都会把system prompt重新编码一遍,第一个请求慢是正常的。chunked prefill建议开,配合--enable-prefix-cache能缓解碎片,但别指望彻底解决,vLLM 0.6.x的KV cache管理确实糙。另外你把max_model_len砍到4096试试,QPS20对7B来说没必要留那么长上下文,显存余量直接给预填充阶段做动态预留。实在不行再考虑TRT-LLM,但迁移成本不低,先把vLLM的--num-gpu-blocks和--max-num-seqs调参玩明白再说。
你这情况我之前跑Yi-34B也撞过,八成不是显存真不够,是vLLM的KV cache预分配策略太保守,加上prefill和decode混排时block管理太死板。建议先把--max-num-seqs调小到8-16试试,同时开--enable-chunked-prefill,能把碎片化摊平不少。另外warmup慢那个正常,vLLM默认会做CUDA graph捕获,第一个请求要等它编译,可以把--enforce-eager打开看下延迟差异,但吞吐会掉一点。如果调完还不行,再考虑换TRT-LLM也不迟,不过它配套生态折腾起来更费劲。
见过类似的坑,你这大概率不是显存碎片,是vLLM默认把预填充和decode的KV缓存池分开了,0.6.3里chunked prefill默认没开,预填充大请求直接吃掉一大块连续显存,decode那边就饿死了。建议先开--enable-chunked-prefill,配合把--max-num-batched-tokens调小到2048试试,比改gpu-memory-utilization管用。第一个请求慢是正常的,vLLM要做CUDA graph捕获,把--enforce-eager关了能缓解,但没法完全避免,真要极致延迟再考虑TensorRT-LLM,不过那个调参更折腾。
显存剩8G但KV cache爆,八成是预填充把显存占死了,chunked prefill值得试,warmup那个首请求慢正常,别太纠结。
这问题我踩过一样的坑,显存剩8G但KV cache报错大概率是碎片化没跑了,vLLM的paged attention在长上下文下确实会这样。建议先试试开chunked prefill,能把预填充和decode的显存争抢缓解不少,另外把max_num_batched_tokens调低点,别让batch太大。第一个请求慢基本就是warmup问题,可以在服务启动后先发个空请求预热下,或者用vLLM的--enable-prefix-caching试试。TensorRT-LLM没必要换,调参空间还很大,先动调度策略再说。
显存剩8G但报KV cache不够,大概率是预填充和decode的显存池没打通,vLLM 0.6.3对7B这种小模型确实容易这样。chunked prefill可以开,但注意别把chunk设太小,否则调度开销反而拖慢吞吐。第一个请求慢正常,vLLM默认没做continuous batch的预热,你可以在服务启动后发个空请求或者用--enforce-eager试试。TensorRT-LLM没必要换,先试试把--max-num-seqs调低到32左右,同时把--block-size改成16,很多时候是block分配太碎导致的问题。
遇到过一模一样的坑,vLLM在0.6.x这个版本对KV cache的预分配策略其实挺保守的,你看到显存剩8G但KV cache报不够,很可能是它把碎片化的显存都算成不可用了,实际可用的连续块没那么大。我建议你先别急着调gpu-memory-utilization,反而试下把max_model_len降到4096看看QPS能不能稳住,因为长上下文会急剧放大KV cache的块分配粒度。chunked prefill在这个场景下值得开,它能把预填充和decode的调度拆开,减少互相挤占,但要注意它可能会轻微增加单token延迟,你得在吞吐和时延之间找个平衡。至于那个warmup慢的问题,其实不是没做对,是vLLM默认的prefix caching没生效,你可以检查下有没有开--enable-prefix-caching,或者干脆在启动时多发送几个带相同前缀的请求预热一下。换TensorRT-LLM的话除非你特别在意极致吞吐,否则我觉得没必要,vLLM调好参数完全够用,而且生态兼容性更好。另外你压测的时候可以观察下vLLM的日志,看看是preempt了还是真的block耗尽,有时候是paged attention的block size设置问题,默认16可能不适合你的场景。
显存还剩8G但KV cache报错,大概率是碎片化没跑了,vLLM在prefill和decode混跑时确实容易这样。你可以试试把--max-num-seqs调小点,比如16或者8,给每个序列多留点连续显存,另外开一下--enable-chunked-prefill,能明显缓解碎片。第一个请求慢正常,vLLM的CUDA graph和显存池都是懒加载的,可以在启动时用curl打一个空请求做warmup,或者直接把--enforce-eager开了看能不能接受速度换稳定性。换TRT-LLM的话学习成本有点高,建议先把vLLM的调度参数摸透再说。