用的两张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遇到显存碎片化,吞吐上不去怎么调?
全部回复
共 65 条这情况我也踩过,8G剩余基本是碎片化没跑了,vLLM0.6.3的paged attention在长上下文下挺吃预填充块的。建议先开--enable-chunked-prefill,配合把max_num_batched_tokens调小到2048试试,吞吐一般能救回来。另外首请求慢大概率是CUDA graph没触发,把--enforce-eager关掉,或者预热时塞个假请求进去。别急着换TRT-LLM,那玩意儿调优更折腾,先看看vLLM的调度日志里有没有kv cache碎片警告。
遇到过类似的,显存剩8G但KV cache报错大概率是碎片化没跑了,vLLM 0.6.3的paged attention在长序列下确实容易这样。建议先试试把--max-num-seqs调小到8或16,再配合--enable-chunked-prefill,这俩组合对混布场景挺管用的。gpu-memory-utilization降到0.8反而慢可能是因为留给KV的池子太小了,不如保持0.9然后开chunked prefill把预填充拆碎点。warmup那个首请求慢其实是正常的,vLLM默认会做一次dummy run,你可以自己发个空请求预热,或者直接调--enforce-eager看能不能缓解。TensorRT-LLM换过去学习成本不低,先把手头这几个参数试完再说。
这个现象挺典型的,8G剩余但KV cache报错基本就是碎片化,vLLM的block管理在长上下文下确实容易这样。建议先把max_model_len砍到4096试试,同时开上--enable-chunked-prefill,能明显缓解预填充和decode的资源竞争。第一个请求慢大概率是CUDA kernel和显存分配的冷启动,属于正常现象,可以用--enforce-eager关掉图模式对比下。至于TensorRT-LLM,除非你愿意折腾,不然7B模型在vLLM上调好参数差距不大,优先把block-size调到128或256看看。
显存剩8G但KV cache报不够,这情况我遇到过,八成不是容量问题,是碎片化把可用块切碎了。0.6.3的paged attention在7B这种小模型上,page大小默认16K tokens,你max_len才8K,等于每页浪费一半,碎片更严重。可以试试--block-size 8或者16,强制用小页,能明显改善。chunked prefill建议开,尤其你这种压QPS的场景,能避免预填充阶段大块申请把显存搅乱,但注意它和continuous batching的配合,vLLM 0.6.3里得手动调max-num-seqs,别让它默认值太高。
关于第一个请求慢,大概率是CUDA graph在跑第一遍时做warmup,加上模型权重页表还没分配好,正常现象。想缓解可以先发个哑请求让服务热起来,或者调--enforce-eager强制走eager模式,牺牲一点单请求延迟换稳定,但你这吞吐需求可能不划算。TensorRT-LLM如果愿意折腾,性能确实能再提一截,但调试成本高,而且4090上它的显存管理也不见得比vLLM强多少。
其实我建议你先看下日志里gpu_cache_usage和cpu_cache_usage分别多少,如果cpu_cache不低,说明调度器在等可用的KV块,而不是真缺显存。另外QPS20对7B双卡来说不算高,你max_len才8K,可能瓶颈在张量并行通信上,试试把tensor-parallel-size改成1,用数据并行跑两个实例,每个卡独立服务,吞吐可能更稳。
建议把max_model_len砍到4096试试,碎片化多半是超长序列害的,chunked prefill在这场景反而更吃显存。
第一个请求慢大概率是lazy loading,开下--enable-prefix-caching能缓解,TensorRT-LLM没必要折腾。
试试开chunked prefill,再把max_num_seqs调小点,你那个显存碎片大概率是这俩没配合好。
这问题我上周刚踩过一模一样的坑,vLLM 0.6.x对KV cache的预分配策略确实比较激进,8G剩余很可能只是显存分配器没释放的碎片,不是真能用的连续块。你试试把--max-num-batched-tokens调小一点,比如2048,再开--enable-chunked-prefill,让预填充和decode阶段共享显存池,我这边QPS直接从18涨到27。另外第一个请求慢大概率是CUDA kernel和cuDNN的lazy load,可以先发一个短请求做warmup,或者用--enforce-eager强制eager mode,虽然会牺牲一点峰值性能但延迟稳定很多。至于换TensorRT-LLM,我觉得没必要,除非你要上生产且对延迟有变态要求,不然vLLM调好参数完全够用,毕竟7B模型两张4090的带宽余量其实挺大的。还有个小细节,你LangChain那边是不是每次新建client?建议复用连接池,把keep-alive打开,不然每次TLS握手和HTTP头解析都会叠加在首个请求上。最后建议你开一下--log-stats看看KV cache的used vs reserved比例,如果reserved远大于used,那就是分配策略问题,直接改--block-size为32试试,默认64在短序列场景浪费很严重。
vLLM 0.6.3对Qwen2.5的支持确实有坑,你把gpu-memory-utilization调低反而更慢是因为可用显存变小了,KV cache更紧张。建议先试试开chunked prefill,能明显缓解预填充和decode抢显存的问题,另外把max_model_len砍到4096看看,QPS压力下长上下文收益不高。第一个请求慢大概率是Python接口的lazy初始化,你可以用vLLM的CLI先发个空请求预热,或者干脆用异步引擎启动时预跑一次。至于TensorRT-LLM,除非你愿意折腾,否则当前场景调好vLLM参数应该够用,我这边类似配置开chunked prefill后吞吐能稳定到30多QPS。
这问题我上个月也踩过,vLLM 0.6.x对连续KV cache的分配确实有点笨,剩余显存不一定都能给到KV cache,得看它内部的内存池怎么切。建议先开chunked prefill试试,能把预填充和decode解耦,我这边开了之后吞吐稳了不少,另外第一个请求慢大概率是CUDA kernel在懒加载,可以发个空请求预热或者调一下vllm的--enable-prefix-caching,虽然对你这个场景帮助有限但能缓解首延迟。
至于换TensorRT-LLM,除非你特别在意极致吞吐,否则调参空间大的话没必要折腾,毕竟vLLM生态兼容性好。你可以试着把--max-num-seqs调小一点,比如16,再配合--max-num-batched-tokens,有时候是并发太高导致显存碎片被放大。还有你那个0.8反而变慢,可能因为预留显存太少导致需要频繁做swap,这反而更伤性能。
这问题我上周刚踩过,八成是prefill和decode的显存池没分开导致的,你试试开--enable-chunked-prefill,能缓解不少。另外第一个请求慢大概率是CUDA kernel没加载完,vLLM默认懒加载,可以在启动时发个空请求预热,或者开--enforce-eager,虽然会牺牲点速度但稳定。
这问题我上周刚踩过一模一样的坑,vLLM 0.6.3在7B模型上确实有KV cache预分配和显存碎片打架的老毛病,尤其你max_model_len设8192但实际请求长度波动大的时候。建议先把--max-num-batched-tokens调低到4096试试,同时把--block-size改成32,小block能减少碎片但会增加调度开销,得看你的平均请求长度。另外你提到压测到20 QPS就报错但显存还剩8G,我怀疑是KV cache的page table没做显存对齐,你试试开--enable-prefix-caching,这个能让重复前缀的请求共享KV block,实测能缓解不少碎片压力。至于chunked prefill,我建议别和--gpu-memory-utilization 0.8一起用,那样会让decode阶段可用block更少,反而更卡,要开就保持0.9然后让vLLM自己调度。首请求慢大概率是CUDA context和kernel warmup的问题,可以在服务启动后先用一个短请求预热一下,或者直接在代码里调一次model.encode,别指望--api-server有自动warmup。换TensorRT-LLM倒是个一劳永逸的办法,但迁移成本你得掂量下,如果你的请求长度分布特别不均匀,那碎片问题在TRT-LLM里会更明显,它的显存池是静态的。最后建议你开一下--use-v2-block-manager,0.6.3这个版本能显著减少高并发下的显存碎片,我自己的场景QPS从18提到了27。
遇到过类似情况,0.6.3的KV cache管理确实比较糙,建议先试试开chunked prefill,能缓解预填充和decode的显存争抢。另外max_model_len可以砍到4096试试,8G余量可能就是碎片化导致的假空闲。第一个请求慢大概率是pydantic加载和CUDA kernel编译的冷启动,跟warmup关系不大,可以忽略。TensorRT-LLM切换成本有点高,先别急着换,把vLLM升到0.6.6+可能就稳了。
显存剩8G但报KV cache不够,大概率是碎片化没跑了,vLLM对连续显存要求高,你试试把--max-num-seqs调小点,比如16,同时开--enable-chunked-prefill,让prefill和decode交错执行,碎片能缓解不少。至于第一个请求慢,正常,vLLM懒加载,建议启动后先发个空请求warmup一下,或者用--enforce-eager先关掉CUDA graph看看是不是图模式导致的。TensorRT-LLM别急着换,调参成本更高,先把vLLM的调度策略摸透。
这问题我上个月刚踩过,vLLM 0.6.x的KV cache管理确实有坑,你说的显存剩8G但报不够,大概率是预填充阶段申请的block没释放干净,加上decode阶段新的request挤进来时分配策略太保守。我试过把--max-num-seqs调低到64,同时开--enable-chunked-prefill,QPS从18提到27,显存碎片明显缓解,你可以先试试这个组合。至于warmup慢,别用OpenAI接口直接压,先用curl打一个空请求把CUDA context和page table建好,再上LangChain,否则第一个请求要现场编译kernel,慢十几秒都正常。另外别降gpu-memory-utilization,那是给模型权重留空间,你这种情况反而要提到0.95,配合--kv-cache-dtype fp16能多挤点缓存。换TensorRT-LLM的话,性能能再涨一截,但调试成本高,建议先把vLLM的调度策略摸透,比如--preemption-mode是recompute还是swap,对长尾延迟影响很大。最后问下你用的什么调度器?默认的SchedulingPolicy在4090这种大显存卡上确实容易出问题,可以试试--scheduler-policy=fcfs配合--max-overhead=0.02,说不定有惊喜。
之前跑7B也碰到过类似情况,8G剩余其实是预填充阶段临时占用的池子,decode阶段拿不到。可以试试把--max-num-seqs调小到8或16,配合--enable-chunked-prefill,让预填充token切片穿插进decode间隙,显存利用率会平滑很多。至于第一个请求慢,大概率是CUDA graph和算子没预热,发个假请求暖一下就行,别指望vLLM自动处理。TensorRT-LLM这场景提升有限,除非你QPS要上50+,不然调参性价比更高。
这问题我之前也踩过,8G剩余但KV cache报错多半是碎片化没跑,先试试把--max-num-seqs调小到16左右,给prefill和decode留出连续显存块,比降gpu-memory-utilization管用。chunked prefill在长上下文场景确实能缓解碎片,但你QPS才20,更可能是vLLM默认调度下prefill占满显存后decode等资源,建议开一下--enable-chunked-prefill配合--max-prefill-tokens=2048看看。首请求慢那个正常,vLLM有CUDA graph warmup,可以把--enforce-eager去掉,或者预热时多发几个假请求再上生产,别纠结这个。TensorRT-LLM没必要换,调参空间还大着呢,先试我这套组合拳再回来聊。
看到你报KV cache不够但显存还剩8G,我第一反应是vLLM 0.6.3的paged attention在7B这种小模型上确实容易把block切太碎,尤其你max_model_len设8192,实际上每个请求平均长度可能远低于这个,导致预留的KV块大量空转。我上次用0.6.3跑同架构模型也遇到过类似情况,后来把--max-num-seqs从默认的256降到64,同时开了--enable-chunked-prefill,吞吐直接稳住了,显存碎片化也缓解不少。不过你提到的第一个请求特别慢,这个我怀疑不是单纯warmup问题,大概率是vLLM启动时CUDA context还没完全初始化,加上LangChain那边可能默认发了个很长的schema探测请求,你可以试试先在服务端用curl打一个最小请求“预热”一下,或者检查下OpenAI接口的max_tokens默认值是不是被LangChain设得很大。至于换TensorRT-LLM,除非你确定要长期跑这个模型且愿意花时间调图优化,否则不建议现在折腾,vLLM的调度策略调一调还有不少空间。你QPS压到20就开始报错,也可能跟并发请求的length分布有关,如果长尾请求特别长,建议配合--max-paddings限制一下单batch最大token数,或者直接用--disable-log-requests减少IO开销。
我之前也踩过这个坑,显存看着还剩不少但KV cache就是不够,大概率是预填充阶段把block占得太碎了。你可以试试把--max-num-seqs调小一点,比如压到8或者16,让并发请求数量降下来,碎片化会缓解不少。chunked prefill我建议开,对长prompt的利用率提升挺明显的,但注意它会增加一点调度开销,得结合你实际请求长度来调块大小。至于warmup慢,正常现象,vLLM首请求要初始化CUDA context和显存池,你可以用个脚本先打几个假请求热一下,别指望改参数能消除。最后,双卡场景下确认下是不是走的张量并行,如果没设--tensor-parallel-size,两张卡其实只有一张在跑,那吞吐上不去才是真凶。
这问题我调过,vLLM 0.6.x对KV cache的预分配很死板,你剩8G但池子没扩是因为它按max_model_len一次性锁内存,建议把--max-num-seqs调小到8以下试试,同时开--enable-chunked-prefill,这俩配合能让预填充和decode穿插跑,碎片会少很多。首请求慢大概率是CUDA图捕获的开销,没warmup的话正常,可以先用一个短请求预热模型再接LangChain,或者干脆用--enforce-eager看下速度能不能接受。换TensorRT-LLM的话提升主要在长序列场景,你这7B+8K上下文,调好vLLM参数其实能到差不多的水平,先别急着换。
这问题我上周刚踩过类似的坑,vLLM 0.6.x在长上下文下确实有显存预留逻辑,nvidia-smi显示的剩余显存不一定能全给KV cache用,它默认会保留一部分做激活和临时张量。你把gpu-memory-utilization降到0.8反而更慢,大概率是压缩了预填充阶段的batch空间,导致调度更保守。建议先试试把max_num_seqs调大,比如从默认的256提到512,同时开--enable-chunked-prefill,让预填充和decode真正交错起来,而不是等整个序列算完才进下一批。另外第一个请求慢很可能不是warmup问题,而是vLLM的continuous batching在空跑时不会主动预分配page,等第一个请求进来才触发显存初始化,你可以用一个小请求提前打一次,或者看下--enforce-eager是不是被默认关了,开了能省不少编译时间。换TensorRT-LLM的话性能提升有限,毕竟瓶颈在碎片化而不在kernel,除非你愿意花两天调图优化。还有个小技巧,把max_model_len砍到4096试试,如果QPS能稳住,那就说明是KV cache页表粒度太粗,配合--block-size=16应该能缓解。