4、性能瓶颈日志识别:TTFT、ITL、吞吐量与批处理异常

性能问题,说白了就是用户觉得“慢”。在vLLM里,慢分好几种。有的慢在第一个字,有的慢在中间的字,有的干脆整体吞吐上不去。我这些年排查下来,发现大部分性能瓶颈都能从日志里找到蛛丝马迹。今天咱们就聊聊怎么从日志里把这些“罪魁祸首”揪出来。

4.1 TTFT异常日志:首Token延迟过高

TTFT,全称Time to First Token。用户问一个问题,到模型吐出第一个字,这个时间就是TTFT。我见过最夸张的一次,TTFT飙到了8秒,用户直接以为服务挂了。

正常TTFT应该在什么范围?

我个人习惯,对于在线推理服务,TTFT控制在500ms以内算及格,200ms以内算优秀。如果超过1秒,就得警惕了。

日志里怎么看?

vLLM的日志会记录每次请求的TTFT。你可以在日志里搜索类似这样的关键字:

INFO 02-28 10:15:23 metrics.py:123] Avg request TTFT: 0.452s
INFO 02-28 10:15:23 metrics.py:124] P99 request TTFT: 1.234s

注意看P99。平均值0.45s看起来还行,但P99到了1.23s,说明有1%的用户体验很差。我建议重点关注P99和P999。

TTFT异常常见原因:
  • 模型加载慢:首次请求时模型还没完全就绪
  • 显存不足:KV Cache分配失败,触发重试
  • 调度器瓶颈:请求排队时间过长
  • 输入过长:预填充阶段耗时太久
避坑指南:我曾经遇到一个案例,TTFT偶尔飙到3秒以上,查了半天发现是某个GPU的NVLink带宽降级了。日志里没有任何报错,只有TTFT异常。所以,TTFT异常不一定只是vLLM的问题,硬件层面也要排查。

4.2 ITL抖动日志:词间延迟不稳定

ITL,Inter-Token Latency,就是每个字之间的延迟。用户感觉“模型说话一顿一顿的”,多半是ITL抖动造成的。

正常ITL应该什么样?

理想情况下,ITL应该是一条平稳的直线。如果出现明显的“锯齿状”波动,那就是抖动。

日志里怎么看?

vLLM的日志会记录每个token的生成时间。你可以通过分析日志中的token时间戳来判断:

# 日志示例(简化)
Token 1: 0.000s
Token 2: 0.045s
Token 3: 0.052s
Token 4: 0.048s
Token 5: 0.210s  # 这里出现了抖动!
Token 6: 0.051s
Token 7: 0.047s

看到Token 5了吗?从0.048s突然跳到0.210s,这就是典型的ITL抖动。为什么会这样?

ITL抖动常见原因:

  • 批处理大小变化:当前批次处理完了,新批次还没准备好
  • 显存带宽争抢:多个请求同时读写显存
  • CPU调度延迟:操作系统把vLLM进程挂起了
  • 模型并行通信:TP或PP的通信延迟不稳定
我的经验:ITL抖动最让人头疼的是它“时有时无”。我建议你做一个持续监控,把ITL的方差也记录下来。方差超过平均值的30%,基本就可以判定为异常抖动。

4.3 吞吐量下降日志:整体性能滑坡

吞吐量,就是单位时间内能处理多少个请求。这个指标下降,说明系统整体性能在退化。

日志里怎么看?

vLLM会输出吞吐量相关的指标:

INFO 02-28 10:15:23 metrics.py:130] Avg throughput: 12.5 req/s
INFO 02-28 10:15:23 metrics.py:131] Avg token throughput: 456.7 tokens/s

如果你发现吞吐量从12.5 req/s降到了8.2 req/s,那就得查原因了。

吞吐量下降常见原因:

原因 日志表现 排查方向
显存碎片化 KV Cache分配失败次数增加 检查显存使用率,考虑重启服务
请求模式变化 平均输入长度变长 分析用户输入分布
硬件降频 GPU利用率下降但温度升高 检查散热和功耗限制
调度策略问题 等待队列长度持续增加 调整max_num_seqs参数
一个真实案例:我记得有一次,吞吐量从15 req/s慢慢降到了5 req/s,持续了3天。查日志发现显存碎片率从5%涨到了35%。最后重启服务解决了。嗯,vLLM跑久了确实会有显存碎片问题,建议定期重启。

4.4 批处理大小异常日志:调度器的“心跳”

批处理大小,是vLLM调度器的核心参数。它决定了每次推理时,有多少个请求被一起处理。批处理大小异常,往往意味着调度器出了问题。

日志里怎么看?

vLLM的调度器日志会记录每次调度的批处理大小:

INFO 02-28 10:15:23 scheduler.py:245] Running batch size: 8
INFO 02-28 10:15:23 scheduler.py:245] Running batch size: 12
INFO 02-28 10:15:23 scheduler.py:245] Running batch size: 4
INFO 02-28 10:15:23 scheduler.py:245] Running batch size: 2  # 异常!

批处理大小突然从12降到2,说明什么?说明有大量请求被提前结束了,或者调度器判断当前无法容纳更多请求。

批处理大小异常常见原因:

  • 请求提前终止:用户取消了请求,或者触发了stop条件
  • 显存不足:无法为更多请求分配KV Cache
  • max_num_seqs设置过小:人为限制了批处理大小
  • 请求长度差异过大:长请求和短请求混在一起,调度器难以优化
避坑指南:我曾经遇到一个情况,批处理大小一直在4和8之间反复横跳。查了半天,发现是某个请求的max_tokens设得特别大,导致它一直占着显存不放。其他请求只能等它结束才能加入批次。所以,检查一下你的请求参数,是不是有人把max_tokens设成了4096?

知识体系总览

下面这张图,是我自己总结的性能瓶颈日志识别框架。你可以把它当作排查时的“地图”:

vLLM性能瓶颈日志识别框架 性能瓶颈日志 TTFT异常 ITL抖动 吞吐量下降 批处理异常 模型加载慢 显存不足 调度器瓶颈 输入过长 批处理变化 显存带宽争抢 CPU调度延迟 模型并行通信 显存碎片化 请求模式变化 硬件降频 调度策略问题 请求提前终止 显存不足 max_num_seqs 请求长度差异大 排查思路:先看TTFT和ITL,再看吞吐量,最后查批处理

这张图把四个性能指标和它们的常见原因串起来了。你排查的时候,可以按这个顺序来:先看TTFT和ITL有没有异常,这两个是用户直接感知的。如果没问题,再看吞吐量是不是下降了。最后,如果批处理大小异常,那基本就是调度器或者显存的问题。

我的建议:别等到用户投诉了才去看日志。把vLLM的metrics接入到你的监控系统里,设置告警阈值。比如TTFT P99超过1秒就告警,ITL方差超过30%就告警。这样你就能在用户发现问题之前,先把问题解决了。

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