用的两张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 条这情况我也踩过,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,说不定有惊喜。