3、性能指标:延迟、吞吐量、首Token延迟(TTFT)、Token间延迟(ITL)的定义与测量
在vLLM推理性能调优中,如果只关注一个数字,往往会误入歧途。延迟(Latency)和吞吐量(Throughput)是宏观指标,而首Token延迟(TTFT)与Token间延迟(ITL)则是微观分解指标。只有将四者组合起来,才能准确判断瓶颈究竟在预填充(Prefill)阶段还是解码(Decode)阶段,进而指导后续的调优动作。
3.1 核心定义:四个指标各代表什么
先明确每个指标的业务含义与技术含义,避免在测量时张冠李戴。
| 指标 | 全称 | 定义 | 关注阶段 | 典型量级(参考) |
|---|---|---|---|---|
| 延迟 | Latency | 从客户端发送完整请求到收到完整响应的总耗时 | 端到端 | 数百ms ~ 数十s |
| 吞吐量 | Throughput | 单位时间内系统处理的请求数或生成的Token数 | 系统整体 | req/s 或 tokens/s |
| TTFT | Time To First Token | 从请求发出到收到第一个输出Token的时间 | 预填充(Prefill) | 50ms ~ 2s |
| ITL | Inter-Token Latency | 相邻两个输出Token之间的时间间隔(即单Token生成耗时) | 解码(Decode) | 10ms ~ 100ms/token |
关键关系:延迟 ≈ TTFT + ITL × (输出Token数 - 1)。这个公式是性能拆解的基石,它把端到端延迟分解为“首Token等待”和“后续Token生成”两部分。
3.2 测量方法:如何准确获取四个指标
测量方式决定了数据的可信度。vLLM 提供了内置的统计接口,同时也支持通过客户端埋点进行端到端测量。
3.2.1 服务端指标获取
vLLM 的 /metrics 端点暴露 Prometheus 格式的指标,其中直接包含 TTFT 和 ITL 的直方图统计:
# 通过 Prometheus 端点获取
curl -s http://localhost:8000/metrics | grep -E "vllm:(time_to_first_token|inter_token)"
# 关键指标示例
vllm:time_to_first_token_seconds_sum{model="llama-3-8b"} 12.345
vllm:time_to_first_token_seconds_count{model="llama-3-8b"} 150
vllm:inter_token_latency_seconds_sum{model="llama-3-8b"} 45.678
vllm:inter_token_latency_seconds_count{model="llama-3-8b"} 1200
通过 sum / count 即可得到平均 TTFT 和平均 ITL。若要观察分位数(如 P95),需要配置 Prometheus 的 histogram_quantile 函数。
3.2.2 客户端埋点测量
对于端到端延迟和业务视角的 TTFT,推荐在客户端进行埋点:
import time
import requests
start = time.perf_counter()
resp = requests.post(
"http://localhost:8000/v1/completions",
json={"model": "llama-3-8b", "prompt": "..."},
stream=True
)
# 记录首Token时间
first_token_time = None
tokens = []
for chunk in resp.iter_lines():
if chunk:
if first_token_time is None:
first_token_time = time.perf_counter()
tokens.append(chunk)
end = time.perf_counter()
ttft = first_token_time - start
itl = (end - first_token_time) / max(len(tokens) - 1, 1)
total_latency = end - start
测量建议:至少测量 100 个请求以上,并记录 P50、P95、P99 三个分位数。仅看平均值会掩盖长尾延迟问题。
3.3 案例:一次典型的性能诊断过程
假设我们有一个 Llama-3-8B 模型部署在单张 A100 上,输入 Prompt 为 500 Token,输出 200 Token。通过监控面板得到以下数据:
- 平均 TTFT = 850ms
- 平均 ITL = 35ms/token
- 端到端延迟 = 850 + 35 × 199 = 7815ms ≈ 7.8s
- 吞吐量 = 200 tokens / 7.8s ≈ 25.6 tokens/s(单请求视角)
从数据中我们可以解读出:
- TTFT 占比约 11%(850/7815),说明预填充阶段不是主要瓶颈。
- ITL 是主要耗时来源,199 个 Token 消耗了约 7 秒,说明解码阶段效率需要优化。
- 如果 TTFT 超过 2 秒,则应该关注 Prefill 的计算优化或输入长度裁剪。
- 如果 ITL 超过 50ms,则应该关注 KV Cache 命中率、显存带宽或批处理大小。
常见误区:不要只优化 TTFT 而忽略 ITL。在长输出场景(如代码生成、长文总结)中,ITL 对总延迟的影响远大于 TTFT。反之,在交互式对话场景中,TTFT 直接影响用户的第一感知。
3.4 吞吐量与延迟的权衡
吞吐量和延迟往往存在矛盾:提高吞吐量(如增大 Batch Size)通常会牺牲单请求延迟。vLLM 的 Continuous Batching 机制正是为了在两者之间取得更好的平衡。
| 场景 | 优先指标 | 调优方向 |
|---|---|---|
| 在线对话/搜索 | TTFT(低延迟) | 减小 Batch Size、启用 Prefix Caching、使用更小模型 |
| 离线批量处理 | 吞吐量 | 增大 Batch Size、使用更长序列、启用 Chunked Prefill |
| 流式输出应用 | ITL(稳定节奏) | 优化 Decode 阶段、增加显存带宽、使用量化 |
3.5 复盘:指标测量中的常见问题
在实际测量中,以下问题会导致数据失真,需要特别注意:
- 冷启动污染:模型首次推理包含权重加载和 CUDA 初始化,应预热 5-10 个请求后再开始统计。
- 并发干扰:在并发请求下,单个请求的 TTFT 和 ITL 会相互影响。应分别测量单请求独占和稳定并发两种场景。
- 网络开销:客户端测量的 TTFT 包含网络往返时间。若需精确测量服务端处理时间,应使用 vLLM 内置指标。
- 输出长度影响:ITL 会随输出长度增加而略微上升(KV Cache 增大导致访存压力),应记录输出长度并分段统计。
- 忽略排队时间:在高负载下,请求可能在队列中等待。此时 TTFT 会显著增大,但这并非模型计算变慢,而是调度瓶颈。
最佳实践:建立性能基线时,固定输入长度(如 512 Token)、输出长度(如 128 Token)、并发数(如 1/8/32 三档),分别记录 TTFT、ITL、端到端延迟和吞吐量。每次调优后对比同一基线,才能准确评估优化效果。