跳转至

第 18 章 推理系统评测与容量规划

开场问题:压测报告说 QPS 达标,上线后 p99 天天超标,而 GPU 利用率只有 60%。差在哪?

18.1 一份可比较的结果必须声明什么

模型、精度与量化方案、硬件型号、并行配置、引擎版本、输入长度分布、输出长度分布、并发或到达率、采样参数、是否命中前缀缓存。少声明任何一项,数字就没法和别人比,甚至没法和自己上周的结果比。

"这张卡上这个模型能跑 3000 tokens/s"是一句没有信息量的话。

18.2 闭环压测会骗你

闭环(发一个请求、等它返回、再发下一个)永远压不出排队问题:系统慢下来时,压测客户端自动就发得慢了,队列永远不会堆积。它测出的是"系统在自己舒服的节奏下能跑多快"。

开环(按设定的到达率持续发,不管前面有没有返回)才能暴露真实的排队行为和 p99。生产流量是开环的,压测也必须是。

另外两个常见自欺:不做 warmup(首次运行含编译、显存分配、图捕获);反复用同一个 prompt(前缀缓存全命中,数字虚高)。

18.3 延迟—吞吐曲线和那个膝点

把并发从低到高扫一遍,画出吞吐和 p99 延迟的曲线。典型形状是:吞吐先线性上升然后饱和,p99 在接近饱和点时突然陡升。

容量规划要定在膝点之前,而不是最大吞吐点。因为真实流量有抖动,压在膝点上意味着任何一次小高峰都变成 SLO 事故。留多少余量取决于流量的波动性,通常是把稳态利用率控制在膝点对应负载的 70%–80%。

18.4 Goodput:把 SLO 写进指标

只有在 SLO 内完成的请求才算数。TTFT 超过 2 秒的请求,用户可能已经关掉页面了,它消耗的算力是纯浪费。

Goodput = 单位时间内满足 SLO 的请求数(或 token 数)。用它做优化目标,很多决策会反转:比如某个配置吞吐更高但 p99 更差,按 throughput 看是赢的,按 goodput 看可能是输的。过载时主动拒绝一部分请求,按 throughput 看是损失,按 goodput 看是保护。

18.5 成本账

最终要能回答:每百万输入 token 多少钱、每百万输出 token 多少钱、每个成功请求多少钱。

算法是:卡的小时成本 ÷ 该小时内的有效 token 产出。但要把这些计入分母之外的损耗——空闲容量(为应对峰值预留的)、失败重试、超出 SLO 的无效产出、以及缓存未命中导致的重复计算。

输出 token 通常比输入 token 贵一个量级(Prefill 可以大批量并行,Decode 每个 token 都要读一遍权重),定价和容量规划都必须分开算。

核心问答

Q:为什么不能只报 tokens/s? 它可能是靠巨大 batch 堆出来的,对应的单请求延迟完全不可接受;而且没区分输入输出。

Q:p99 高,先查什么? 把 p99 请求的时间拆成排队、Prefill、Decode 三段,看哪段长。通常是排队(容量不足或调度不公)或被长 Prefill 打断。

Q:为什么压测要模拟真实长度分布? 长度直接决定 Prefill 工作量、KV 占用和 Decode 时长。用固定长度压测得到的结论在真实流量下经常不成立。

Q:怎么公平比较两个引擎? 同模型、同精度、同硬件、同长度分布、同到达率,比 goodput 和每百万 token 成本,而不是比峰值吞吐。