文章

LLM 容量压测生产实战:用 Timed Trace、Burstiness 与 Tail-SLO Gate 找到真实安全 QPS

LLM 容量压测不能只跑固定并发和平均延迟。本文结合 vLLM、AIPerf 与 MLPerf,讲清 Timed Trace、突发流量、尾延迟门禁与安全 QPS 的生产评估方法,教你找到上线前真实可靠的容量拐点。

LLM 容量压测生产实战:用 Timed Trace、Burstiness 与 Tail-SLO Gate 找到真实安全 QPS

生成式推理服务的压测结果,常常被测试方法本身误导。最常见的报告是:固定 50 或 100 并发,跑若干分钟,然后记录平均 TTFT、平均吞吐和 GPU 利用率。这样的数字可以做单机优化对比,却不足以回答生产环境最重要的问题——在真实请求到达方式下,这套集群到底能稳定承受多少流量?

原因在于生成式推理并不是固定耗时 RPC。请求的输入长度、输出长度、是否多轮、到达间隔和突发程度都会改变排队、批处理和显存占用。两个平均 QPS 相同的流量,一个均匀到达、另一个在几秒内集中爆发,对尾延迟造成的压力完全不同。

因此,容量测试的目标不应是寻找“最大吞吐”,而应寻找 Safe QPS:在代表性 workload 下,系统持续满足既定 Tail SLO 的最高请求率。

背景:为什么“跑满 GPU”不等于知道系统容量

GPU 利用率 100% 只说明硬件在忙,不说明系统在“正确地”忙。生产容量真正的度量标准,是系统在满足业务承诺的前提下能接住多少外部流量。一个把 GPU 打满但 p99 尾延迟已经失控的服务,和一台跑不满但尾延迟稳定的服务,前者并不具备更高的可用容量。

本文结合 vLLM、NVIDIA AIPerf 与 MLPerf 的 Server 场景,讲清四件事:为什么固定并发会高估容量、为什么平均长度不代表真实 workload、为什么 Burstiness 必须作为独立变量、以及如何用 Tail-SLO Gate 找到真正的容量拐点。

核心原理一:先区分闭环并发与开放环到达率

固定并发为什么会掩盖过载

固定 concurrency 本质上是闭环负载:一个请求完成后,客户端才继续补下一个。当服务端开始变慢时,客户端自己也会变慢,新请求注入速度随之下降。

这种方式适合观察“同时有 N 个用户时”的体验,却可能高估真正的在线承载能力,因为生产流量通常不会因为你的 GPU 变慢就自动停止到达。

相比之下,按 request rate 驱动的开放环负载会按照预定时间继续发请求。服务端一旦处理不过来,队列、TTFT 和端到端尾延迟就会真实暴露出来。

vLLM 当前的 bench serve 可以直接使用 --request-rate 控制请求率,并支持 Poisson 或 Gamma 分布生成到达时间;--burstiness 小于 1 时会产生更突发的到达模式。AIPerf 同样支持 constant、poisson、gamma 等 arrival pattern。

生产压测至少应分别跑两类实验:

  1. Closed-loop concurrency sweep:观察不同并发下的单请求体验和 GPU 饱和区间。
  2. Open-loop request-rate sweep:观察固定外部到达率下何时出现排队失控和 Tail SLO 破坏。

核心原理二:平均长度不代表真实 workload

LLM 请求成本与 token 长度高度相关。只用“输入 1K、输出 256”这样的固定样本,往往会把真实业务中的长上下文、短回答、长回答和混合流量全部抹平。

更合理的方法是先从生产或预生产日志提取匿名化 workload profile,至少保留:

  • 请求时间戳;
  • input token length;
  • output token length;
  • 会话或 workload class;
  • 必要时保留用于复现前缀相似性的 hash 信息,而不是原始业务文本。

vLLM 最新的 timed_trace 数据集直接支持 timestampinput_lengthoutput_lengthhash_ids 等字段,并可使用 trace 中的时间信息进行 self-timed replay。AIPerf 也支持带时间戳的固定调度 Trace Replay。

一个最小化的匿名 trace 可以类似:

{"timestamp": 0,   "input_length": 1200, "output_length": 52, "hash_ids": [0, 1, 2]}
{"timestamp": 105, "input_length": 1800, "output_length": 26, "hash_ids": [0, 3, 4, 5]}
{"timestamp": 274, "input_length": 1300, "output_length": 52, "hash_ids": [1, 4, 6]}

AIPerf 官方示例可按原始时间戳固定调度:

aiperf profile \
  --model YOUR_MODEL \
  --endpoint-type chat \
  --streaming \
  --url localhost:8000 \
  --input-file custom_trace.jsonl \
  --custom-dataset-type mooncake_trace \
  --fixed-schedule

这类 trace 的价值不只是“更像生产”。它还能暴露固定长度测试很难出现的问题:长上下文集中到达、会话突发、上下文窗口越界,以及同一个平均 QPS 下完全不同的队列形态。

核心原理三:Burstiness 必须作为独立变量

容量测试经常只扫 QPS,却忽略 Burstiness。实际上,平均 20 QPS 可以是每 50ms 均匀一个请求,也可以是短时间连续几十个请求、随后长时间空闲。

vLLM 的 benchmark 支持通过 Gamma 分布调节 burstiness;AIPerf 也把 arrival pattern 与 smoothness 暴露为参数。这意味着压测矩阵不应只有 QPS 一维,而应至少包含:

  • request rate;
  • burstiness / arrival pattern;
  • input/output length distribution;
  • concurrency cap;
  • workload class。

建议把生产容量结果画成多条曲线,而不是一个数字。例如同样是 30 QPS,分别给出 Poisson、较平滑 Gamma、较突发 Gamma 和真实 Trace Replay 的 p95/p99 指标。这样才能知道系统对突发流量是否敏感。

核心原理四:用 Tail-SLO Gate 找容量拐点,而不是追求最高 TPS

生成式服务的容量曲线通常存在明显拐点:在某个到达率之前,吞吐随流量增长;超过拐点后,吞吐增长变慢,但排队时间和尾延迟快速上升。

因此 Safe QPS 应定义为:在指定 workload profile、测试时长和硬件配置下,同时满足全部业务 SLO 与稳定性门禁的最高持续 request rate。

门禁至少包含:

指标含义
Success Rate不能通过超时、拒绝或错误来“换吞吐”
TTFT p95/p99交互请求最直观的等待感受
ITL / TPOT p95/p99生成过程是否卡顿
E2E Latency p95/p99完整请求体验
Queue Time / Queue Depth是否开始持续积压
Output Tokens/s服务端有效产出能力
GPU / HBM / CPU用于解释瓶颈,而不是作为最终 SLO

门禁配置应来自业务场景,而不是照抄其他公司的绝对阈值。例如可以把发布规则表达成:

capacity_gate:
  success_rate: ">= ${SUCCESS_SLO}"
  ttft_p95: "<= ${TTFT_P95_SLO}"
  ttft_p99: "<= ${TTFT_P99_SLO}"
  itl_p99: "<= ${ITL_P99_SLO}"
  e2e_p99: "<= ${E2E_P99_SLO}"
  queue_growth: "no_sustained_growth"

MLPerf 的 Server 场景同样采用随机到达并设置 latency constraint,而不是只报告离线吞吐。其 DeepSeek-R1 文档还特别提示,Server target QPS 通常需要人工寻找;它有时大约是 Offline QPS 的 80%,但在部分系统上甚至可能低于 50%。这正说明 Offline throughput 不能直接当成在线容量

工程落地:建立四层压测体系

第一层:Micro Benchmark

目标是比较单项配置,例如 TP/EP 布局、量化方式、内核版本或 GPU 型号。此时可使用固定输入输出长度和稳定 concurrency,以降低变量数量。这一层回答“哪个配置更快”,不回答“生产能扛多少流量”。

第二层:Synthetic Capacity Sweep

使用多个 input/output bucket,扫描 request rate 和 burstiness。每个点必须经过 warmup,并保存 per-request 结果而不仅是汇总均值。vLLM bench serve 支持保存详细请求指标,也能直接输出 TTFT、TPOT、ITL 与 E2E 的 percentile。建议在 CI 或性能实验平台中,把每个 benchmark run 的模型版本、推理引擎版本、GPU、并行配置和参数全部作为 metadata 保存。

第三层:Timed Trace Replay

从真实业务流量采样并匿名化,保留时间戳和 token length 分布。对同一份 trace 做 A/A 与 A/B Replay,可用于比较:推理引擎升级、GPU 型号变化、并行策略变化、模型版本变化、调度参数变化。这里最重要的是保持 workload 不变,否则很难判断性能变化来自系统还是流量。

第四层:Soak + Burst Test

短压测容易错过内存碎片、连接池、缓存热度变化和慢性队列增长。最终发布前应至少增加持续稳态测试,并在稳态期间插入突发流量段,观察系统能否恢复到原来的队列和尾延迟水平。

如何把测试结果转成容量规划

最终不要输出“单卡 35 QPS”这种孤立结论,而是输出一个 Capacity Envelope

  • Interactive workload:Safe QPS = X;
  • Long-context workload:Safe QPS = Y;
  • Bursty workload:Safe QPS = Z;
  • 对应 GPU 数量、模型配置和 Tail SLO;
  • 至少预留一档业务增长和故障冗余空间。

其中 X/Y/Z 应来自实际测试,不应预先写死。容量规划时还要明确 N-1 或单副本故障后的 SLO,因为“正常状态刚好跑满”通常不是可运营的生产容量。

常见误区

误区正确做法
只看平均 TTFT关注 p95/p99,并按 input length、tenant 或业务类型分桶分析
固定并发跑到最高 TPS 就算容量固定并发会形成闭环反馈,适合性能扫描,不足以定义在线安全 QPS
所有请求都用相同 token 长度至少需要短、中、长 bucket,最好最终使用真实 trace
用 ignore_eos 的吞吐直接用于业务容量该结果只适合配置对比,不宜直接作为容量结论
只压平均流量,不压突发真实系统常死在 10 秒峰值而非 1 小时平均值,Burstiness 必须显式测试

上线检查清单

  • 已分别完成 closed-loop concurrency 和 open-loop request-rate 测试。
  • 已覆盖生产 input/output token length 分布,而不是只有一个固定长度。
  • 已至少测试 Poisson/突发流量或真实时间戳 Trace Replay。
  • 已保存 p95/p99 TTFT、ITL/TPOT、E2E、成功率与队列指标。
  • 已找到 Tail SLO 开始明显恶化的容量拐点,而不是只记录最高 TPS。
  • Safe QPS 由业务 SLO Gate 决定,并留有故障与增长余量。
  • benchmark artifact 已记录模型版本、推理引擎版本、GPU、并行参数和测试数据版本。
  • 发布前完成持续稳态测试,并确认突发结束后队列能够恢复。

参考资料

  1. vLLM — vllm bench servehttps://docs.vllm.ai/en/latest/cli/bench/serve/
  2. NVIDIA AIPerf — Trace Replay with Mooncake Traces:https://docs.nvidia.com/aiperf/benchmark-modes/trace-replay-with-mooncake-traces
  3. NVIDIA AIPerf — Command Line Options:https://docs.nvidia.com/aiperf/reference/command-line-options
  4. NVIDIA AIPerf — Comprehensive LLM Benchmarking:https://docs.nvidia.com/aiperf/getting-started/ai-perf-comprehensive-llm-benchmarking
  5. MLCommons — Llama 2 70B: An MLPerf Inference Benchmark for Large Language Models:https://mlcommons.org/2024/03/mlperf-llama2-70b/
  6. MLPerf Inference — DeepSeek-R1:https://docs.mlcommons.org/inference/benchmarks/language/deepseek-r1/

常见问题

为什么固定并发压测容易高估 LLM 的在线容量?
固定并发属于闭环负载:请求变慢后,客户端自然降低新请求注入速度,可能掩盖排队和过载。生产容量评估应同时使用按请求率驱动的开放环负载,并观察 TTFT、ITL、端到端尾延迟和错误率。
Timed Trace 与随机合成流量应该二选一吗?
不应该。合成流量适合系统化扫描容量曲线和复现实验,Timed Trace 用于复现真实的长度分布、突发与空闲周期。两者组合比单独使用任何一种都更可靠。
什么是安全 QPS?
安全 QPS 不是设备能跑出的最高吞吐,而是在代表性流量下,同时满足成功率、TTFT、ITL、端到端尾延迟及稳定性门禁的最高持续请求率。
是否可以直接用 Offline tokens/s 推算线上 QPS?
不建议。Offline benchmark 更接近机器能持续产出多少 token,而在线系统还受请求到达、排队、TTFT/ITL SLO 和长度分布影响,应通过 Server-style workload 实测安全 QPS。