本地大模型排队与批处理调优实操

说明如何用 vLLM 的 max_num_seqs、max_num_batched_tokens 与 KV cache 调整本地服务,并用 TTFT、TPOT、完成吞吐和抢占记录验证效果。

做本地部署大模型时,排队和批处理要从 max_num_seqs、max_num_batched_tokens 与 KV cache 容量一起调。依据 vLLM 的 vllm serve CLI 参考,前两个参数分别限制单次迭代处理的序列数和 token 数,并不是同一个“并发数”。每次只改一个参数,再比较 TTFT、TPOT、完成吞吐和抢占情况,才能判断等待发生在哪个环节。

调优前先固定本地部署大模型的测试条件

先锁定模型、输入长度、输出上限、请求并发和流式返回方式,各轮测试不要改变这些条件。--max-model-len 表示 prompt 与 output 合计的上下文长度;不设置时会从模型配置推导。同一参数的可选范围为 0 到 1,未指定时使用 0.92。vLLM CLI 参考中的这些定义应在测试前确认。

启动后先查看日志中的 GPU KV cache size。按照 vLLM 的 Parallelism and Scaling 文档,这一行表示 GPU KV cache 同时能够容纳的 token 总量。随后固定客户端、请求超时、预热方式和测量时段,并保存每次实际使用的参数。

实操:先建立可复现的基线

当前 vLLM SchedulerConfig 源码给出的默认值是:max_num_batched_tokens 为 2048,max_num_seqs 为 128。可以先用文档默认值启动,再替换模型和业务上下文上限:

vllm serve YOUR_MODEL \
  --max-model-len YOUR_CONTEXT_LENGTH \
  --max-num-seqs 128 \
  --max-num-batched-tokens 2048 \
  --gpu-memory-utilization 0.92

将 YOUR_MODEL 替换为实际模型标识,将 YOUR_CONTEXT_LENGTH 替换为应用的上下文上限。这只是可复现的起点,不是性能承诺;完成基线请求后,优先只调整 max_num_seqs 或 max_num_batched_tokens 中的一项。

排队变长时先判断是否发生抢占

不要把 max_num_seqs 直接称为队列长度,它只是每轮处理的序列上限。所引文档没有说明超过该上限的请求究竟在客户端、网关还是调度器等待,这部分需要检查入口日志和响应时间。

依据 vLLM 的 Optimization and Tuning 文档,KV cache 空间耗尽时,vLLM 可能抢占请求,并在空间恢复后重新计算;V1 默认使用 RECOMPUTE,而不是 SWAP。对于频繁抢占,文档建议先提高 gpu_memory_utilization,或者降低 max_num_seqs、max_num_batched_tokens,以减少每批并发请求及其 KV cache 需求。

降低上限可能减少抢占,却也可能让更多请求等待更久。因此不能只看服务是否报错,还要同时比较 TTFT、TPOT 和完成吞吐。

批处理参数按指标目标调整

同样依据 vLLM 的 Optimization and Tuning 文档,V1 会在条件允许时默认启用 chunked prefill,并优先调度 decode 请求。较小的 max_num_batched_tokens 有利于 token 间延迟,文档给出的例子是 2048;较大的值有利于 TTFT,因为它能在单批中处理更多 prefill token。

如果目标偏向完成吞吐,文档建议将 max_num_batched_tokens 设置为大于 8192,尤其是模型较小且 GPU 较大时。这个建议不是所有模型的固定答案:首字延迟、逐 token 间隔和总吞吐需要分别验证,不能只保留其中一项。

调优后怎样验证

每轮只改一个参数,重复发送同一组请求,并记录配置、完整响应数、错误数、TTFT、TPOT 和完成吞吐。可以用下面的方法计算处理吞吐:

处理吞吐 = 完成的请求数 / 有效测量时长

如果结果要称为 MLPerf 提交,依据 MLPerf Inference 规则,每次提交都必须使用 LoadGen;LLM benchmark 记录首 token 延迟 TTFT 和生成 token 之间的平均间隔 TPOT,被测系统则是接受测量的硬件与软件资源集合。同一规则还区分了负载方式:Server 场景按 Poisson distribution 发送查询并报告可支持的最大 Poisson throughput;Offline 场景在开始时发送全部样本,没有延迟约束,报告测得的吞吐。不同场景的结果不能直接混为同一指标。

常见出错点

  • 同时修改多个参数:即使结果改善,也无法判断是哪项参数产生作用。
  • 比较时改变上下文或输出长度:输入规模变化会干扰 TTFT 和批处理判断。
  • 把完整请求时长当成 TTFT:TTFT 只表示首 token 到达之前的延迟。
  • 忽略 API 包装层:如果瓶颈出现在 FastAPI 路径中,FastAPI 的并发文档说明,普通 def 路径操作函数会在外部线程池中执行;不确定依赖库是否支持 await 时,官方建议使用普通 def。调 vLLM 参数时应保持包装层不变。
  • 把默认值当成最佳值:默认值只能提供基线,最终配置仍要由固定负载下的指标决定。

这些步骤依据正文所链接的官方文档整理,未运行或测量;使用前应按当前版本复核。

资料来源