3、推理速度基础:吞吐量与延迟、首Token延迟(TTFT)与Token间延迟(ITL)、批处理(Batching)原理

聊到vLLM推理,大家最关心的无非两个事:快不快,以及稳不稳。快,指的是吞吐量高、延迟低;稳,指的是首Token别卡太久,后续Token也别忽快忽慢。

我个人习惯把推理速度拆成三个维度来看:吞吐量延迟批处理效率。这三个东西互相牵制,你调好一个,另一个可能就崩了。今天咱们就把它们掰开揉碎讲清楚。

3.1 吞吐量与延迟:一对天生的冤家

先说吞吐量。说白了,就是单位时间内能处理多少个请求。比如你的服务每秒能处理100个请求,那吞吐量就是100 req/s。vLLM里常用的是每秒输出Token数(Tokens per second)。

延迟呢?就是一个请求从发出去到拿到完整回复的时间。用户感知最直接的就是这个。

你想想看,吞吐量和延迟是不是天生矛盾?你拼命塞请求进去,吞吐量上去了,但每个请求排队时间变长,延迟就飙升。反过来,你只处理一个请求,延迟很低,但吞吐量惨不忍睹。

我在项目中遇到过这种情况:为了追求高吞吐,把batch size拉到最大,结果单个请求的延迟从200ms飙到2秒。用户直接投诉“卡死了”。所以调优时,你得先明确业务场景——是聊天场景(低延迟优先)还是离线批量处理(高吞吐优先)。

核心公式:
吞吐量 = 总输出Token数 / 总耗时
平均延迟 = 所有请求延迟之和 / 请求数

3.2 首Token延迟(TTFT)与Token间延迟(ITL)

这两个指标,是vLLM调优里最容易被忽视的细节。我刚开始做推理优化时,只盯着总延迟看,结果发现用户反馈“打字半天才出第一个字”。这就是TTFT的问题。

3.2.1 首Token延迟(TTFT)

TTFT,全称Time to First Token。指的是从请求发出到模型输出第一个Token的时间。这个时间主要花在:

  • Prefill阶段:模型处理输入Prompt,计算KV Cache
  • 网络传输:请求从客户端到服务端的往返
  • 调度排队:请求在vLLM调度器里等待被处理

我记得有一次,用户反馈某个大模型“反应慢”,我查了半天,发现是Prompt太长(超过2000 Token),Prefill阶段耗时占了TTFT的80%。后来我建议用Prompt压缩分块Prefill,TTFT直接降了60%。

避坑指南: 我曾经以为TTFT只跟模型大小有关,后来发现调度策略影响也很大。vLLM默认的FCFS(先来先服务)调度,在大并发下TTFT会急剧恶化。建议开启优先级队列,把短请求优先处理。

3.2.2 Token间延迟(ITL)

ITL,Inter-Token Latency。指的是相邻两个Token输出之间的时间间隔。这个指标直接决定了“打字速度”的流畅感。

ITL主要受Decode阶段影响。Decode阶段是自回归的——每生成一个Token,都要重新计算一次。vLLM通过KV CachePageAttention来加速,但ITL依然受限于:

  • Batch size:batch越大,每个Token的计算时间越长
  • 模型大小:7B模型ITL通常在10-20ms,70B模型可能到50-100ms
  • 显存带宽:Decode阶段是显存带宽瓶颈,不是算力瓶颈

你想想看,如果ITL是50ms,那每秒只能输出20个Token,用户会觉得“一个字一个字往外蹦”。我建议把ITL控制在30ms以内,这样用户体验才过得去。

注意: TTFT和ITL是此消彼长的关系。你为了降低TTFT而减小batch size,ITL可能会因为资源利用率低而变差。反过来,你为了降低ITL而增大batch size,TTFT又会飙升。所以调优时,要同时监控这两个指标

3.3 批处理(Batching)原理

批处理是vLLM提升吞吐量的核心手段。但批处理不是简单的“把多个请求塞一起算”,这里面门道很多。

3.3.1 静态Batching vs 动态Batching

静态Batching:把所有请求收集齐了,一次性算完。优点是实现简单,缺点是等待时间长——你得等最后一个请求到了才能开始算。

动态Batching:来一个请求就处理一个,不等。vLLM用的是Continuous Batching(连续批处理),这是它的杀手锏。

Continuous Batching的原理是:每个请求独立进行Prefill和Decode,但共享GPU计算资源。比如请求A在做Prefill时,请求B已经在Decode了。这样GPU始终处于忙碌状态,不会因为等待而闲置。

我记得第一次看到Continuous Batching的效果时,挺震撼的。同样的硬件,静态Batching的吞吐量只有200 Token/s,换成Continuous Batching直接飙到800 Token/s。说白了,就是把GPU的空闲时间压榨到了极致

3.3.2 Batch Size的选择

Batch size不是越大越好。我建议你根据显存大小模型大小来定。一个经验公式:

最大Batch Size = (可用显存 - 模型权重显存) / (每个请求的KV Cache显存 + 激活显存)

举个例子,一张A100 80GB显卡,部署7B模型(权重约14GB),每个请求的KV Cache约2GB(假设序列长度4096)。那么:

可用显存 ≈ 80GB - 14GB = 66GB
每个请求显存 ≈ 2GB + 0.5GB(激活)= 2.5GB
最大Batch Size ≈ 66 / 2.5 ≈ 26

但实际中,我建议留20%的余量,所以Batch Size设到20左右比较安全。

调优口诀:
TTFT看Prefill,ITL看Decode
Batch Size看显存,Continuous Batching保吞吐

3.4 知识体系图:推理速度核心指标

下面这张图,是我自己总结的推理速度调优框架。你可以把它当成一个检查清单,每次调优时对照着看。

推理速度核心指标与调优框架 吞吐量 Tokens/s 或 req/s 延迟 TTFT + ITL 批处理 Continuous Batching Batch Size 模型并行度 TTFT Prefill + 调度 ITL Decode + 显存带宽 调度策略 FCFS / 优先级 显存 调优目标:在满足延迟约束下,最大化吞吐量 TTFT < 500ms, ITL < 30ms, 吞吐量尽可能高 注:实际调优需结合硬件、模型、业务场景综合决策

3.5 实战建议:如何平衡这三个指标

说了这么多理论,最后给点实战建议。我自己的调优流程是这样的:

  1. 先定延迟目标:比如TTFT不超过500ms,ITL不超过30ms。这是硬约束。
  2. 再调Batch Size:从1开始往上加,直到TTFT或ITL超标为止。这个临界点就是最优Batch Size。
  3. 开启Continuous Batching:vLLM默认就是,但要注意调度策略。如果并发高,建议用优先级队列
  4. 监控显存:用nvidia-smi或vLLM自带的metrics,看显存是否打满。如果显存有剩余,可以继续加Batch Size。
  5. 反复迭代:调优不是一次性的。业务高峰期和低谷期,参数可能不一样。我建议写个自动调优脚本,定期跑压力测试。
一个小技巧: 如果你发现TTFT很高,但ITL正常,问题大概率在Prefill阶段。可以试试分块Prefill(Chunked Prefill),把长Prompt切成小块,边算边输出。vLLM 0.4.0之后支持这个功能。

嗯,以上就是推理速度基础的全部内容。吞吐量、延迟、批处理,这三者就像三驾马车,你得让它们齐头并进。下一节咱们会深入KV Cache与PageAttention,那是vLLM提速的核心秘密。


公众号:蓝海资料掘金营,微信deep3321