版本信息最后核对:2026-10-25
推理延迟变高的定位与修复:把 TTFT、TPOT、排队、KV Cache、网络和 GPU 分开看。
用户感觉“回答变慢了”,可能表现为首字迟迟不出现、流式输出中间卡顿、整体生成时间变长,或者吞吐没有明显下降但 P95/P99 延迟变差。监控上常见 num_requests_waiting 上升、KV Cache 使用率接近上限、GPU 利用率忽高忽低,也可能一切指标都正常,只有客户端观测到延迟。
先把三个量分开:TTFT 是从请求发出到收到第一个输出 token 的时间,包含排队、预处理和 prefill;TPOT 或 ITL 描述首 token 之后每个输出 token 的间隔,主要反映 decode 与批处理调度;端到端时延还受输出长度、网络和客户端解析影响。一个指标变差不代表同一根因。
同一服务可能对不同请求表现不同:短提示长输出慢,通常看 decode;长提示短输出慢,通常看 prefill 和 tokenizer;高峰期集体变慢,优先看排队与容量;只有远端客户端慢而服务端指标正常,重点查网络、代理缓冲和流式解析。
用相同模型、相同提示、相同输出上限和相同并发复现一次,分别记录客户端与服务端时间。压测时固定数据集和请求速率,不要用一条随手请求的体感代替基线。
curl -N -sS http://<host>:<port>/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"<served-name>","messages":[{"role":"user","content":"<prompt>"}],"max_tokens":128,"stream":true}'
查看服务端指标。不同 vLLM 版本的指标名可能变化,先列出实际存在的名称:
curl -s http://localhost:8000/metrics \
| grep -Ei 'vllm|ttft|tpot|itl|e2e|queue|waiting|running|kv_cache|prefix|spec_decode'
观察点:
waiting 持续上升而 running 已接近上限、KV Cache 使用率也高:先按容量和排队处理。waiting 不高、GPU 利用率也不高:查 tokenizer、调度、CPU 争抢、代理或网络,不要盲目加 GPU。同时看 GPU 和主机:
nvidia-smi --query-gpu=index,utilization.gpu,memory.used,memory.total,clocks.sm,power.draw,temperature.gpu --format=csv -l 1
nvidia-smi topo -m
top -H
vmstat 1
核对输入 token 数,而不是只看字符数。聊天模板、系统提示和工具定义都会增加 token:
python - <<'PY'
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("<model-dir>")
messages = [{"role": "user", "content": "<prompt>"}]
ids = tok.apply_chat_template(messages, tokenize=True, add_generation_prompt=True)
print("tokens:", len(ids))
PY
建立可比基线。固定提示集、输出上限、并发和流式开关,记录 P50/P95/P99 的 TTFT、TPOT 和端到端时延,同时保留吞吐与错误率。冷启动与稳定运行分开记录;不要拿空闲时的一次请求和高负载时的平均值直接比较。
先判断瓶颈阶段。用短输出测首 token,用固定较短提示测长时间 decode;再逐步增加提示长度和输出长度。若延迟随提示长度增长明显,重点查 prefill、tokenizer 和长请求调度;若随输出长度增长,重点查 decode、KV Cache 与批处理。
检查队列和缓存。观察等待请求、运行中请求、KV Cache 使用率与抢占迹象。若等待请求持续增长,先确认总容量和输入输出长度;若缓存压力高但 GPU 计算利用率不高,检查批大小、上下文上限和前缀复用策略,而不是只增加并发上限。
验证 tokenizer 成本。在服务所在主机测一次 tokenize 与聊天模板耗时,并统计输入 token 分布。如果客户端发来的提示远比基准长,问题可能是提示构造、系统消息膨胀或检索结果拼接过多,而不是引擎退化。
分别测本机与远端。在服务所在主机直连一次,再通过网关或公网调用一次,比较首字节、token 间隔和总时长。若本机快、远端慢,检查 DNS、TCP 重传、TLS、反向代理缓冲、连接复用和客户端是否启用了流式读取。
观察 GPU 的实际状态。确认是否有其他进程、是否发生降频或温度限制、是否存在跨 NUMA 或跨节点通信。GPU 利用率只是一个信号:利用率低可能是 CPU 或调度受限,利用率高也可能只是大量低效小批次在空转。
核对批处理与上下文参数。一次只改一个参数,并用同一负载复测。减少上下文或并发可能改善时延,但也会降低吞吐;开启 chunked prefill 或前缀缓存前,先确认请求是否共享前缀、长提示占比是否足够。参数名和默认行为随版本变化,以当前引擎文档为准。
单独评估投机解码。在同一模型、同一数据集上分别关闭和开启投机,比较 TTFT、TPOT、吞吐和接受率。只有接受率足够高且 decode 是主要瓶颈时,收益才可能出现;低并发和短输出要充分测试,避免用更复杂的配置换来更差的首字延迟。
排除版本和配置漂移。对比最近变更:引擎版本、驱动、CUDA、模型 revision、tokenizer、聊天模板、代理配置、副本数和资源限制。把基线负载在旧版本上重跑一次,确认是代码变化还是环境变化。
max_tokens,避免少数长请求占满 KV Cache。为不同模型和接口分别定义 TTFT、TPOT 与端到端时延目标,按输入输出长度和流式模式拆分看板。持续记录排队数、KV Cache、GPU 时钟与利用率、tokenizer CPU、代理延迟和客户端首字节时间,避免只看一张 GPU 利用率图。
上线前用真实提示分布压测并保留容量余量,在引擎升级、模型更换和提示模板修改后重跑基线。给长上下文入口设置配额,限制无界输出;把代理缓冲、流式转发和客户端读取方式纳入联调。把性能回退与版本、配置、流量变化放在同一时间线上。
合上页面,先回答,再展开对照。
小程序版
微信扫码,随时查命令