3.1 批处理参数调优


3.1 批处理参数调优

本节导读:批处理是vLLM高吞吐的根基。本节深入Continuous Batching的调度机制,逐个解析关键参数的含义、默认值与调优方法,并给出一套"压测→定位→调整"的标准调优流程。

学习目标

  • 理解Continuous Batching与静态批处理的本质区别
  • 掌握 max_num_batched_tokensmax_num_seqs 等核心参数的调优方法
  • 理解Chunked Prefill对首Token延迟的影响
  • 学会用压测数据驱动参数决策,而非凭感觉配置

核心概念

从静态批处理到Continuous Batching

传统静态批处理要等一批请求全部生成完才能释放,短请求被长请求拖累,GPU大量空转。vLLM的Continuous Batching按iteration粒度调度:每个step重新组批,已完成的请求立刻退出、新请求立刻插入,配合PagedAttention的块级KV管理,实现接近理论峰值的利用率。

Prefill与Decode的矛盾

  • Prefill(处理输入):计算密集,一个大prompt就能吃满GPU
  • Decode(逐token生成):访存密集,单序列利用率极低,靠并发数堆利用率

两者混跑时互相干扰:大prompt的prefill会阻塞decode,推高TPOT(每token延迟)。Chunked Prefill把长prefill切成小块分步执行,牺牲少量TTFT换取decode流畅,是延迟敏感场景的标配。

关键参数速查表

参数 默认值 作用 调优方向
max_num_batched_tokens 2048(开chunked prefill时8192) 每step最多处理的token数 吞吐不足→调大;TTFT超标→调小
max_num_seqs 256 同时运行的序列数上限 并发场景调大,显存紧张调小
max_model_len 模型上限 单请求最大长度 按业务真实分布下调,释放KV显存
enable_chunked_prefill 近版本默认开 长prefill分块执行 在线服务保持开启
scheduler_delay_factor 0.0 攒批延迟因子 纯吞吐场景可上调至0.3~0.6

分步实战

步骤 1:建立基线压测

调参前先有数据。用vLLM自带工具测出基线:

python -m vllm.entrypoints.cli.benchmark.serve \ --model Qwen/Qwen2.5-7B-Instruct \ --dataset-name sharegpt --dataset-path sharegpt.json \ --num-prompts 500 --request-rate 10

关注四个指标:TTFT(首token延迟)、TPOT/ITL(后续token延迟)、吞吐量(output tok/s)、P99。没有基线,后续任何调整都无法判断好坏。

步骤 2:识别瓶颈类型

curl -s http://localhost:8000/metrics | grep -E "num_requests_(running|waiting)"
  • num_requests_waiting 持续堆积、running打满 max_num_seqs并发上限瓶颈,优先调大 max_num_seqs
  • running不高但GPU利用率低、TTFT长 → 每step token预算瓶颈,调大 max_num_batched_tokens
  • 显存频繁不足、出现preemption日志 → 过载,反向收缩参数

步骤 3:调整参数并对比

vllm serve Qwen/Qwen2.5-7B-Instruct \ --max-num-batched-tokens 16384 \ --max-num-seqs 512 \ --max-model-len 8192 \ --gpu-memory-utilization 0.92

每次只改一组参数,跑同样的压测脚本,记录指标变化。推荐用表格管理实验:

实验 max_batched_tokens max_num_seqs TTFT P99 吞吐
基线 8192 256 1.8s 1200
+tokens 16384 256 1.2s 1650
+seqs 16384 512 1.3s 1780

步骤 4:处理Preemption(抢占)

显存不足时调度器会preempt部分序列(丢弃KV Cache,之后重算),日志特征为Sequence group ... is preempted。频繁preemption意味着吞吐白白损失:

  1. 降低 max_num_seqs,减少同时在跑的序列
  2. 下调 max_model_len 到业务真实需要的长度
  3. 检查输入长度分布——被几个超长prompt拖垮时考虑前置截断

完整示例:一套在线服务的参数决策

某RAG客服场景:输入约2000 token、输出约300 token、峰值并发300:

vllm serve Qwen/Qwen2.5-7B-Instruct \ --max-model-len 4096 \ --max-num-seqs 320 \ --max-num-batched-tokens 8192 \ --enable-chunked-prefill \ --gpu-memory-utilization 0.9

决策逻辑:输入长输出短→TTFT是主要矛盾→保持chunked prefill并给足token预算;并发已知峰值300→max_num_seqs 略高于峰值即可;max_model_len 按"输入+输出+余量"设4096,省下的显存全部换成KV Cache容量。

常见问题 FAQ

Q1:max_num_batched_tokens 是不是越大越好?
不是。它是每step的计算预算,调大能提高吞吐和降低TTFT,但超过GPU单step算力后收益递减,且会拉长单step耗时、恶化decode延迟。经验值:A100/H100上8192~32768之间扫参。

Q2:chunked prefill开了反而吞吐下降,为什么?
chunked prefill偏向降低TPOT,吞吐上本身有轻微开销。纯离线批处理场景(只要总吞吐不在乎延迟)可以关闭,换取更大的整段prefill。

Q3:max_num_seqs 设得远高于实际并发,有坏处吗?
有。它决定了调度器允许的排队在跑序列数,过高会让大量序列进入运行态争抢KV Cache,引发preemption连锁反应。按真实峰值并发×1.2设置即可。

Q4:离线批量推理该用什么参数?
离线场景用 LLM 类 + 大 max_num_seqs(如1024)+ 一次喂入全部prompt,让continuous batching自动组批;gpu_memory_utilization 可直接给到0.95,因为没有并发请求需要预留缓冲。

Q5:如何观测每个step的调度行为?
vllm serve--otlp-traces-endpoint 可输出trace;更简单的办法是周期抓取 /metricsnum_requests_runningnum_requests_waitingtoken_usage 三个指标画曲线。

最佳实践与避坑

  • 避坑一:直接抄别人的参数配置。参数最优值高度依赖模型大小、GPU型号、输入输出长度分布,必须用自己的业务流量压测;
  • 避坑二:把 max_model_len 设成模型上限(如128K)"以备不时之需"——KV Cache按最大长度预留会浪费大量显存,宁可按95分位长度设小;
  • 实践:调优顺序固定为"max_model_lengpu_memory_utilizationmax_num_seqsmax_num_batched_tokens",先释放显存再谈并发;
  • 实践:每次变更通过git管理启动命令与压测结果,可随时回溯某次性能劣化的原因。

本节小结

本节解析了vLLM批处理调优的核心:理解prefill/decode的资源矛盾,用压测数据识别瓶颈类型,再对症调整 max_num_batched_tokensmax_num_seqs。记住"有基线、单变量、做记录"三原则。下一节把视角从单卡扩展到多GPU并行。

延伸阅读


作者与出处
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 引力.04c560的小龙虾 转发
评论区 (0)
U