用的两张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剩余其实是碎片化,不是真不够。建议先把max_model_len降到4096试试,QPS20的场景下长上下文利用率没那么高,腾出来的连续空间可能比调utilization更管用。chunked prefill可以开,但注意要配好max_num_batched_tokens,不然小请求多了反而调度开销大。至于第一个请求慢,我这边是显存预热的问题,可以先发个空请求或者用curl打一下health端点再挂到LangChain上,能改善不少。TensorRT-LLM性能确实强,但迁移成本高,建议先把vLLM的调度参数玩明白再说。
这个现象我蹲过,八成是prefill和decode的KV缓存没做隔离,vLLM 0.6.3对长序列的paged memory管理还比较粗,剩的8G基本是零散块。建议开--enable-chunked-prefill,再把--max-num-seqs调小到8左右,让单batch别那么贪,比调gpu-memory-utilization有效。warmup慢那个正常,OpenAI接口首次会触发CUDA kernel编译和图捕获,你可以先发个空请求预热,或者把--enforce-eager打开试试,牺牲点延迟换稳定。先别急着换TRT-LLM,这版本配置还没吃透的话换框架只会更抓瞎。
显存还剩8G但报KV cache不够,大概率是预填充峰值把连续显存占死了,vLLM的block管理在这种混合负载下容易碎。建议先开chunked prefill,再把max_num_batched_tokens调小到2048试试,能缓解峰值压力。第一个请求慢是正常的,vLLM的CUDA graph和显存池要冷启动,可以在服务启动后发个空请求预热一下。TensorRT-LLM在这场景提升有限,调vLLM参数性价比更高。
说实话你这情况我上周刚踩过一模一样的坑,vLLM 0.6.x对Qwen2.5的KV cache管理确实有点弱智,尤其prefill和decode混跑的时候。建议先把--enable-chunked-prefill打开,然后--max-num-batched-tokens调到4096试试,我这么改完QPS能稳到35不掉KV。另外那个首请求慢大概率是CUDA graph没触发,你可以加个--enforce-eager对比下,但别长期开,吞吐会掉。别急着上TRT-LLM,那玩意调起来更折腾,先把vLLM这几个参数吃透再说。
遇到过类似的,vLLM 0.6.x的KV cache管理确实有点笨,prefill和decode混跑时碎片化挺常见的。你试试把--enable-chunked-prefill加上,同时把--max-num-seqs调小到8左右,我这边QPS能稳到30。另外那个首请求慢,大概率是lazy loading导致前几个token要现场编译CUDA kernel,可以先用一个假请求预热,或者设一下--enable-prefix-caching,能省不少事。TensorRT-LLM的话除非你愿意折腾,不然别急着换,vLLM调一调够用了。
这问题我上个月刚踩过一遍,最后发现瓶颈根本不在显存总量,而是vLLM默认的KV cache预分配策略太保守了。你降到0.8反而更慢是因为预填充阶段能用的block变少,长请求排队更严重。建议先把--max-num-seqs调小到8试试,同时开--enable-chunked-prefill,这能把预填充的显存占用打散,跟decode阶段错峰。另外你提到第一个请求慢,大概率是CUDA graph没触发,vLLM 0.6.3对短输入默认不走graph,可以试试在首次请求前发个2048长度的假请求热一下。至于换TensorRT-LLM,除非你完全放弃动态shape和LangChain的灵活性,否则调试成本不划算。我最后是靠把--gpu-memory-utilization设回0.92,再配合--max-num-batched-tokens=4096,压到32 QPS才稳。你那个8192的max_model_len如果实际用不到那么长,砍到4096能省出至少2G显存给KV cache。还有个细节,两张4090之间NVLink带宽对7B模型影响不大,但如果你开张量并行,block大小建议设成16而不是默认的8,碎片能少一半。
遇到过类似的坑,vLLM对KV cache的预算是按总显存算的,但实际峰值在prefill阶段会临时多占一块,你剩的那8G很可能就是被它卡着不敢用。建议先试试开chunked prefill,把prefill切成小块跟decode交错执行,显存利用率会平滑很多;另外--max-num-seqs调小到16或8也能减少碎片。第一个请求慢大概率是CUDA kernel和graph在warmup,可以在服务启动后发个假请求预热一下,或者开--enforce-eager看看是不是graph捕获导致的延迟。TensorRT-LLM没必要换,这规模的问题vLLM调参能解决。
这情况明显是碎片化,开chunked prefill试试,首请求慢是正常的,vLLM本来就要编译优化。
建议直接上PagedAttention的v2版本,或者把max_model_len砍到4096,碎片能缓解不少。
换TRT-LLM成本太高,先调一下--enable-chunked-prefill,再把block size调小点,应该能好很多。
这问题我上周刚踩过类似的坑,两张4090跑7B其实挺尴尬的,显存算力都卡在中间。你那个显存剩8G但KV cache不够,大概率不是碎片化,而是vLLM的预分配机制压根没把剩下的显存算进去,它按max_model_len和gpu-memory-utilization提前划好KV池,你降到0.8反而让池子更小,自然更慢。chunked prefill可以开,但你这QPS 20的压力下,它主要缓解长提示词的调度阻塞,对吞吐提升有限,更建议先试试--enable-prefix-caching,LangChain那边每次请求带的历史消息如果前缀重复,命中缓存后第一个请求慢的问题能缓解很多。另外你提到warmup,vLLM 0.6.3确实有冷启动延迟,可以在服务启动后发一个假请求预热,但根治还得看是不是max_num_seqs设太小,默认256对于7B可能不够,试着调到512,同时把--max-parallel-loading-workers设成2,让两张卡并行加载权重。至于换TensorRT-LLM,除非你愿意花一两天做模型转换和调优,否则短期内vLLM调参足够,毕竟7B在4090上理论吞吐能到50+ QPS,你现在的瓶颈更像配置没匹配上实际负载。
我之前也踩过这个坑,vLLM 0.6.3对KV cache的预占用策略挺迷的,你剩8G但报不够大概率是预填充阶段把可用块锁死了,建议把--max-num-seqs调小到32左右试试,同时开--enable-chunked-prefill,让预填充和decode交错着来。第一个请求慢正常,因为要做CUDA graph和算子warmup,可以发个空请求预热,或者用--enforce-eager先跑通再切回graph模式。TensorRT-LLM别急着换,那玩意儿调优更折腾,先把这几个参数组合试一遍,我上次调完吞吐翻了快一倍。
chunked prefill开起来试试,0.6.3这版本对Qwen2.5的碎片管理确实一般,别急着换TRTLLM。
这问题我上个月刚踩过,vLLM 0.6.x的KV cache管理确实有坑,特别是长上下文+多并发的时候,预填充和decode的显存池是分开算的,你剩的8G很可能被PagedAttention的block预留了但没实际用上。建议先试试把--max-num-seqs调低到4或8,再配合--enable-chunked-prefill,这俩组合拳对碎片化改善挺明显的。另外你提到的warmup慢,大概率是vLLM在启动时做的CUDA graph捕获和显存预分配,第一次请求会触发完整的profile过程,正常现象,但如果你用LangChain的async接口,可以提前发个空请求把engine热起来。至于换TensorRT-LLM,说实话除非你QPS要求超过50,不然vLLM调好参数完全够用,别折腾了。还有个细节,确认下你的KV cache dtype是不是fp16,如果模型本身用bf16,这里不匹配也会导致显存利用率打折扣,可以看下日志里的GPU KV cache usage百分比,如果低于50%就说明调度策略没生效,试着用--kv-cache-dtype fp8_e5m2试试,能省不少显存。
显存还剩8G但KV cache不够,大概率是碎片化没跑了,你可以试试把--max-num-seqs调小点,比如压到4或8,给prefill和decode留出连续空间。chunked prefill建议开,能明显缓解峰值抖动,但注意配合--enable-chunked-prefill把block size调成16或32试试。第一个请求慢是因为vLLM的CUDA graph和显存池要冷启动,可以在服务启动后先发个固定长度的假请求预热,别用LangChain直接压。至于换TensorRT-LLM,除非你愿意折腾编译和动态shape,不然vLLM调好参数后7B模型两卡足够。
显存还剩8G但KV cache报不够,大概率是碎片化没跑,vLLM 0.6.3的block管理确实糙了点。建议先把--max-num-seqs调小到16试试,再把--enable-chunked-prefill打开,这版本对长prompt的调度提升挺明显的。至于第一个请求慢,正常,因为要初始化CUDA context和CUDA graph,你可以在服务启动后发个空请求做warmup,或者用--enforce-eager模式,虽然慢点但能避免首token延迟。TensorRT-LLM的话,除非你QPS要上50+,否则没必要折腾,调好vLLM参数够用了。
遇到过类似的,8G剩余其实是被碎片吃掉了,vLLM的KV cache是预分配的,0.9和0.8都不解决问题,建议把--max-num-seqs调小到32或者16,同时开--enable-chunked-prefill,让prefill和decode交错调度,吞吐能稳不少。第一个请求慢大概率是CUDA kernel和graph在warmup,可以发个空请求预热,或者用--enforce-eager先跑一遍再切回默认模式。换TRT-LLM的话调优成本挺高的,4090上vLLM调好参数其实够用。
开chunked prefill吧,0.6.3这版本碎片化挺严重的,8G余量其实都被卡住了。
这问题我前两天刚踩完坑,vLLM 0.6.3的KV cache管理确实有点呆,你那个8G剩余其实是预留给当前batch的连续块的,但预填充和decode混跑时它不会动态回收,所以看着有空间实际没法用。建议先把--max-num-seqs调小到128试试,我这边压到64之后显存碎片化明显缓解,吞吐反而升了15%。chunked prefill可以开,但记得把--preemption-mode设成recompute,不然遇到长序列抢占时更卡。至于warmup慢那个,正常,vLLM第一次请求要编译CUDA kernel,你可以用--enable-prefix-caching加上启动时多发几个假请求预热,LangChain那边第一次调用别走代理直连就快了。换TensorRT-LLM没必要,除非你愿意为那点提升折腾一周,先调参吧。
试试开chunked prefill,再把max_num_seqs调小点,碎片能缓解不少。TensorRT-LLM没必要换,调参够用。
这问题我上周刚踩完坑,vLLM 0.6.3对Qwen2.5的prefix caching支持有点迷,你那个第一个请求慢大概率是没开--enable-prefix-caching,加上LangChain每次会带不同的system prompt,cache全失效了。显存剩8G但KV cache不够,典型的预填充峰值把block表撑爆了,你试试把--max-num-seqs调小到8或者16,别让它一次塞太多请求进来抢block。chunked prefill我觉得要开,但注意配合--max-num-batched-tokens设个512或者1024,不然预填充和decode互相卡死。另外你说降gpu-memory-utilization反而更慢,是因为vLLM的显存预留是按比例算的,留太少了反而触发频繁的swap,建议回到0.95然后把--block-size改成64试试,block粒度大点能减少碎片。TensorRT-LLM的话除非你愿意折腾engine构建和动态shape,否则这个规模的项目不值得,vLLM调参空间还没榨干呢。还有个小技巧,--enable-chunked-prefill=true时把--max-paddding-length关掉,能省点显存。我这边同样两张4090跑7B,QPS稳定在35左右,你可以参考下。
遇到过类似的,0.6.3这个版本对KV cache的预分配挺保守的,你试试把--max-num-seqs调小到16或者8,能显著减少碎片,另外chunked prefill建议开,对长请求混短请求的场景提升很明显。第一个请求慢大概率是CUDA graph和显存池没预热,可以在启动后发个空请求warmup一下,或者用vLLM的--enable-prefix-caching也能缓解。至于换TRT-LLM,除非你愿意花时间折腾,不然现阶段vLLM调好参数其实够用。