P50发绿,P99是灾难
你的仪表盘显示 P50 延迟 800 毫秒,SLA 写的是两秒以内。一切正常。然后有人提交工单:它转了 30 秒才放弃。查日志一看,P99 是 28 秒。这个 35 倍的差距不是监控 bug,也不是可以配置超时字段消掉的异常值,它来自输出长度的重尾分布本身,以及推理系统的批处理把这种分布放大了一层。
我在处理这类问题上踩过的第一个坑,是把端到端延迟当单一指标看。只报一个 P99 数字,你会同时看到两种完全不同的故障:预填充阶段被长 context 撑爆,和解码阶段被预填充插队打断。两者混在一起的时候,改什么都像在试探。
TTFT 和 ITL 是两笔债
把时间拆成两段:
- TTFT(首个 token 时间),对应预填充成本,大致随未缓存的 prompt token 数量线性增长。32000 token 的上下文,TTFT 可能比 320 token 的请求长 100 倍。
- ITL 或 TPOT(token 间延迟),对应解码过程的稳定性。解码受显存带宽限制,单步算一个 token,正常时中位几十毫秒。
拆开之后诊断路径就很清楚了。如果 TTFT P99 高而且 ITL P99 正常,问题在上下文长度的异质性或者 KV 缓存被逐出;优先去想长度感知路由和对话感知的缓存策略。反过来,如果 TTFT 正常但 ITL P99 高,那基本是预填充打扰了正在解码的批处理,得去看调度器。
生产环境的测量里,vLLM 的一个内部负载把 P99 token 间延迟做到过 1.76 秒,而中位 ITL 只有几十毫秒。这里说的就是纯 ITL 的尾部,不是端到端。
重尾来自哪里:解码级的等待放大
解码批处理的行为是 GPU 并行推进所有请求,直到批内最长的那个结束。一个请求生了 4000 token,另外九个各 200 token,十个请求一起承担接近 4000 token 的解码成本。有研究统计过代码、摘要和问答任务上的输出长度分布,最大值与中位数的比值在 2 到 4 倍之间:代码任务上的 Llama 模型达到 3.27 倍,长文本任务到 4 倍。非流式场景下,这个比值直接落到 P99 和 P50 的端到端比值上,批处理再把它放大一次。
排队论能解释后半截:平均排队延迟和服务时间的二阶矩成正比,不是均值。几个失控的长输出请求就能把 E[S²] 推高,其他请求一起受罪。批处理也不方便用重排解决,因为生成过程中的抢占成本很高。
再叠加 agent 层面的卷积。一步调用里 3 倍的输出长度比值,五步链路走下来就变成 15 倍以上的端到端比值。这也是为什么 agent 工作流在报表上会突然把端到端 P99 拖得不像单步统计能解释的样子。
几种让 P50 变好、P99 更烂的常见操作
无脑加大 batch size
吞吐优先的直觉是扩大批。(怎么算都行,但先说清一件事:大约 20 到 30 个请求之后,> 具体阈值随 GPU 和模型大小变化),超过计算饱和拐点后再往批次里塞请求,延迟会非线性飙升。那条吞吐-延迟曲线左边是平的,右边是陡的。越过拐点用吞吐换 P99,很难是笔划算的交易。
标准重试打在慢请求上
传统索引后退避假设的是瞬时故障。LLM 响应慢不等于失败了,模型还在跑。对一个三秒没返回的请求做退避重试,等于在已经饱和的系统上再造一个在途重复请求,批次进一步滑过拐点,别人的 P99 就一起崩。
优先保 TTFT
交互式工作负载里这看起来很对,但优先给新请求预填充就会打断正在进行的解码批,制造出生成停顿的气泡,ITL 的尾部立刻抬头。每一次以抢占 decode 为代价换来的 TTFT 改善,本质上是在把延迟转移到已经在生成的那些请求身上。
纯 LRU 清 KV 缓存
LRU 假设访问模式统一,但对话历史让上下文长度高度不均。一段冷门但一直在进行的对话的 KV 缓存可能很快被逐出,等用户下一个请求进来只能做一次完整的重新预填充,TTFT 尖峰正好出现在他参与度最高的时候。有研究把对话感知缓存与按新近度加预期重用价值的策略做过对比,LRU 逐出模式抬高了 SLO 违规率。
降低方差的几个可直接上的手段
分块预填充
把长 prompt 按 token 预算切块,跟解码步交替执行。解码受显存带宽限制,计算资源本身有富余,所以插进去的预填充块不会明显降低解码吞吐,同时消除了长预填充一把抢走解码批的尖峰。测量数据显示,大模型上用分块预填充后 P99 token 间延迟从 1.08 秒降到 0.29 秒,约 3.7 倍。这项现在是主流推理框架的默认开关了,如果你还在手调,先确认它不是被关掉的。
长度感知路由
长短请求塞同一批会带来 padding 和 SM 间不对齐,相当于把长度同质批次的延迟开销额外抬高 10 到 110%。按预测的序列长度分桶路由,按不同的工作负载,P99 尾部延迟能降 25 到 69%,中位也接近的改善,总吞吐大致翻倍。长度预测不必做得太重,用输入特征跑个很轻的 XGBoost 分类器,输出长度的平均绝对误差大概 5% 就足够把请求送进正确的桶。
准入控制与配额的账
把活跃批次控制在饱和拐点以下、留出 20 到 30% 的富余容量,延迟能接近线性扩展。按富余容量做主动扩缩容,平均有效吞吐比反应式更高,因为根本不用进非线性区。对重尾的工作负载硬性限输出长度(比如 1600 token),可以把排队延迟减少 58%,同时有 70% 的请求完全不需要截断就能服务完。
投机解码看时机
小模型草稿加目标模型一轮验证,接受率 60 到 80% 时 ITL 能降 2 到 3 倍。但这里有个坑:收益在 GPU 利用率偏低的时候最明显,饱和状态下草稿模型会争抢计算资源,加速比就回去了。生产上有的部署报告过并合场景的性能数字(FP8 量化 H100 上的 Llama 3.1-70B 有 2.31 倍速度、3.6 倍吞吐的提升),但这建立在负载留有余量的前提下。所以要结合 GPU 利用率判断,50% 以下再谈,用过了就是白忙。
另外不要对比数据只看加速比。投机解码不改善 TTFT 的尾部,它明显的是解码这一段。TTFT P99 高的时候上这东西只是白忙。
对冲请求的边界
provider 层面的尾部可以用对冲来兜。设个延迟阈值(比如 P50 500 毫秒的端点放到 2 秒),过了阈值并行发第二家,谁先回用谁的。P50 两倍的阈值下重复请求的成本大致十分之一,如果慢的原因在那一侧(真的),>那个 provider 响应变慢,P99 的改善会非常明显。但要小心,对冲和原来的重试不要在代码地里互相叠成一层层的乘法放大。对于同样性质的慢,保留一个机制就行。
监控上该记什么
直方图分箱要把可能范围铺满:50ms、100ms、200ms、500ms、1s、2s、5s、10s、30s。如果你的标准监控直方图只读到 2 到 5 秒,那么所有长尾都会挤在溢出桶里,尾部的形状就完全看不到了。
几个值得单独记录的点:P50、P95、P99 的 TTFT(聊天场景里 P95 TTFT 超过 1 到 2 秒就应当鸣);P99 的 ITL(交互场景超过 500ms 就该查解码停顿);有效吞吐(同时满足 TTFT 和 ITL SLO 的请求占比,这是比任何单一百分位的端到端延迟都更好的 SLA 指标);KV 缓存利用率(领先信号,冲到 90% 以上往往预告 TTFT 会抬头);P95 队列深度(批批饱和的预警)。
平均值最好不要拿来做主要信号。均值受尾部牵动很大,还不容易对应到具体的用户。分位和分位之间本来就是独立序列,P50、P95、P99 分开看已经够了。
两条最短的排障起手
- 先拆 TTFT 和 ITL 的 P99。TTFT 坏就去查上下文长度分布与 KV 缓存命中,ITL 坏就查预填充对解码的打扰。
- 低头看输出长度分布。如果 P99 输出长度超过 P50 的 3 倍,说明尾巴的源头不在基础设施上,重尾本身才是。这种情况下限额或长度路由带来的收益比任何别的小打小闹都大。
转载请注明出处: 皮哈皮阿
本文的链接地址: https://blog.phpat.com/ai-engineering/666.html
微信或手机浏览器扫一扫,随时随地随心阅读与分享
-
推理成本下降之后:模型路由、KV Cache 与端侧推理
上个月一个团队拿着账单来找我:模型单价降了,费用却涨了三倍。看完调用链就明白了,问题不在单价,在用法。单位 token 便宜,不等于每次任务便宜。
2026/10/10
-
2026 年 AI 应用评测:从单轮打分到多轮轨迹评估
一个 Agent 的评测分数从 72% 涨到 81%,团队很高兴,直到发现它学会了在失败时直接结束任务,把“没做完”算成了“无需回答”。评测设计错了,指标越好看越危险。
2026/10/19
-
推理模型的流式输出:thinking 块怎么流
推理模型的流式输出不只是逐字渲染:思考块、正文、工具调用参数混杂在 SSE 流里,客户端要按字段分流、独立缓冲、支持中途中断。记录接通义千问与智谱过程中的判断和踩坑。
2026/10/24
-
动态拼批不是开个开关:线上拼批的取舍与门禁
在线服务里的动态拼批和离线批量推理是两码事。窗口时长、KV Cache 水位、批内参数对齐共同决定拼接能否成立。上线前该盯的是 p99 和显存峰值,而不只是吞吐。
2026/10/25
-
长度惩罚参数调优:常见参数名字容易混淆
长度惩罚在主流 API 里并不存在。真正管长度的是 max_tokens 和 stop sequences,frequency、presence、repetition 惩罚管的是用词重复和新词探索。把这些旋钮分开,能避免输出被截断、术语被替换成同义词两类故障。
2026/10/23
-
推理服务排队延迟的分层观测:从请求数到Token账本
盯 QPS 和 P99 看不到排队延迟长在哪。把这件事拆成入口→上游准入队列→后端等待→batch 解码四层,用 vLLM 暴露的排队与 KV 缓存指标做层级归因,讨论分层之后仍然看不见的部分与取舍。
2026/10/27
京公网安备11011402053654 
@muffin:链接已更新,分类图像功能...
AI网址导航模版图标库更换指南
作者大大,图标库邀请链接失效了,麻烦更新...
AI网址导航模版图标库更换指南
太好看了,快点更新!
友情链接
@戴墨镜的刘备:哈喽,路过点赞。
vue.js组件之手写签名板vue-signature-simple
太好看了,快点更新!太棒了!👍真的很赞!
vue.js组件之手写签名板vue-signature-simple
你写得非常清晰明了,让我很容易理解你的观...
Emlog插件RSS订阅器发布