文章

LLM 推理容量规划生产实战:用 Token 吞吐压测与队列水位估算 GPU 余量

本文讲解如何把大模型在线推理从事后扩容改成可压测、可估算、可预警的容量工程,覆盖Token吞吐、队列水位、P99 TTFT、GPU余量和上线检查清单,帮助团队提前识别瓶颈并做出定量的扩容决策。

背景问题:LLM 容量不是”QPS 乘以平均耗时”

传统 Web 服务做容量规划时,团队通常会从 QPS、平均耗时和 CPU 利用率出发,用简单的线性模型估算所需资源。但大模型在线推理有本质不同:

  • 请求成本高度不均匀。一个 200 Token 输入、50 Token 输出的客服问答,和一个 8K Token 输入、2K Token 输出的分析任务,对 GPU 的占用不在同一个量级。
  • 推理分为 prefill 和 decode 两阶段。前者主要处理输入上下文,计算密集;后者逐 token 生成输出,显存带宽密集。二者的资源瓶颈点不同。
  • 尾延迟的根因不单是模型计算慢,更多来自队列等待、批处理拥塞、KV Cache 水位和长输出请求的资源占用。

所以,LLM 容量规划不能只问”这个模型能抗多少 QPS”。更准确的问题应该是:在给定输入/输出 Token 分布、P99 TTFT 目标、P99 端到端延迟目标和峰值流量形态下,当前 GPU 池还能承受多少新增负载?什么时候必须扩容?什么时候只是调度参数、队列策略或限流策略没有配好?

核心原理:把容量拆成 Token、队列和 SLO

1. 用 Token 分布替代平均请求

容量规划的输入不应该是单个”平均请求”。至少要记录以下分布:

字段作用
input_tokens决定 prefill 压力和 KV Cache 初始占用
output_tokens决定 decode 持续时间和用户等待时间
total_tokens用于估计上下文窗口和 KV Cache 水位
arrival_rate不仅要有均值,还要有峰值、突刺和周期性
tenant / scenario不同业务流量分开建模,避免短问答掩盖长任务

NVIDIA GenAI-Perf 的 LLM 指标中包含 TTFT、inter-token latency、request latency、input/output sequence length、output token throughput 和 request throughput,并支持按并发或请求速率产生压测负载。这类指标比单纯 QPS 更适合作为 LLM 推理容量基线。

2. 用队列水位解释尾延迟

当 GPU 池接近饱和时,用户感知的延迟不一定先体现在 TPOT 上,而是先体现在 queue timeTTFT 上——新请求需要等待调度槽、KV Cache、批处理窗口或副本资源。

vLLM 暴露的生产指标可以直接把”模型慢了”拆解为具体原因:

num_requests_running          # 当前正在运行的请求数
num_requests_waiting           # 当前排队等待的请求数
kv_cache_usage_perc            # KV Cache 使用率
request_queue_time_seconds     # 请求排队时间
request_prefill_time_seconds   # Prefill 阶段耗时
request_decode_time_seconds    # Decode 阶段耗时
time_to_first_token_seconds    # 首 Token 延迟 (TTFT)

借助这些指标,团队可以从”模型慢了”的模糊判断,升级为”排队慢、prefill 慢、decode 慢、KV Cache 紧张还是调度拥塞”的精确定位。

3. 用 P99 TTFT 作为第一道容量红线

对聊天、搜索增强问答、Agent 控制面等场景,TTFT 往往比完整响应耗时更能反映用户体感。TTFT 超标通常意味着请求已经在入口、队列或 prefill 阶段发生拥塞。

容量规划可以采用以下原则:

可用容量 = 在 P99 TTFT 和 P99 queue time 未超过 SLO 时的最大稳定负载 安全余量 = 可用容量 − 预计峰值负载 扩容阈值 = 安全余量低于业务设定比例,或连续窗口内 SLO burn rate 超标

关键不是追求某个固定 GPU 利用率,而是找到 “延迟开始非线性上升”的拐点。很多推理服务在 GPU 利用率远未接近 100% 时,P99 已经不可接受;也有一些场景 GPU 看似利用率不高,但被长尾请求、KV Cache、显存碎片或单租户突刺拖垮。

工程落地:从一次压测到可复用容量模型

第一步:采集真实流量足迹

不要直接用随机 prompt 压测生产容量。更可取的做法是从真实请求中脱敏采集容量相关字段

{
  "timestamp_ms": 1730000000000,
  "tenant": "risk-review",
  "scenario": "long_report_qa",
  "model": "llama-70b",
  "input_tokens": 6420,
  "output_tokens": 820,
  "stream": true,
  "priority": "normal"
}

注意这里只需要容量字段,不应保存原始敏感 prompt。Token 长度、到达时间、模型、租户和场景已经足够支撑大部分容量评估。

第二步:建立压测矩阵

压测矩阵至少包含四类场景,不能只跑一条曲线:

场景目标关注指标
基线压测找到单副本或单 GPU 池的稳定吞吐TTFT、TPOT、request latency、tokens/s
峰值压测验证业务高峰是否有余量P95/P99 queue time、P99 TTFT
长尾压测验证长输入、长输出、Agent 任务的影响KV Cache 水位、decode time、等待队列
混合流量回放验证真实场景下的容量拐点SLO 达标率、租户公平性、错误率

NVIDIA GenAI-Perf 支持 synthetic input,也支持从文件读取数据集,并可以指定输入输出长度、请求数、并发和请求速率。对生产团队来说,最有价值的是 “真实流量回放 + 峰值放大”,而不是只跑固定长度的短 prompt。

第三步:把压测结果转成容量曲线

一次压测的输出不要只留在报告里。建议把结果整理成容量曲线

模型: llama-70b
硬件: 8 × H100
场景: mixed_chat_agent
SLO: P99 TTFT ≤ 800ms, P99 E2E ≤ 12s

稳定区间: 0–120 req/s      # SLO 全部达标,队列水位稳定
风险区间: 120–150 req/s     # queue time 开始抬升,TTFT 波动增大
失稳区间: >150 req/s        # P99 TTFT 非线性上升,SLO 持续违反

建议生产水位: ≤100 req/s    # 保留约 20% 峰值余量

这条曲线比”平均 QPS 150”有用得多,因为它告诉运维和业务方:什么时候是安全的,什么时候只是短时可承受,什么时候会进入尾延迟失控。

第四步:把队列指标接入自动扩缩容

如果部署在 Ray Serve、Kubernetes 或类似平台,扩缩容指标不应只用 CPU 或 GPU 利用率。Ray Serve 的 autoscaling 支持通过 target_ongoing_requests 控制每个副本的期望并发数;Kubernetes HPA 也支持基于自定义指标做水平扩缩容。

LLM 服务更适合引入以下自定义扩缩容信号:

autoscaling_signals:
  - p99_time_to_first_token_seconds
  - p99_request_queue_time_seconds
  - num_requests_waiting
  - kv_cache_usage_perc
  - prompt_tokens_per_second
  - generation_tokens_per_second
  - slo_burn_rate

缩容策略应比扩容保守。 LLM 模型副本通常有权重加载、预热、KV Cache 建立和调度稳定过程,缩容过快会造成下一波流量又重新冷启动。因此需要 cooldown、stabilization window 和 warm pool 配合。

容量估算公式:先粗算,再用压测修正

工程上可以用一个粗略模型做第一轮估算:

峰值输入 Token/s  = 峰值请求数/s × P95 input_tokens
峰值输出 Token/s  = 峰值请求数/s × P95 output_tokens

所需 GPU 数 ≈ max(
  峰值输入 Token/s / 单 GPU 稳定 prefill Token/s,
  峰值输出 Token/s / 单 GPU 稳定 decode Token/s
) × 安全系数

⚠️ 这个公式只能用于预估,不应直接作为采购或上线依据。它忽略了队列、批处理、KV Cache、不同请求长度混合、租户突刺和硬件故障的影响。inference-fleet-sim 论文也指出,LLM 推理 GPU fleet sizing 依赖完整 token-length distribution、routing policy 和 queueing dynamics,很多场景没有简单的闭式答案。

因此,推荐流程是:

  1. 用粗算模型给出第一版 GPU 数量。
  2. 用真实 token 分布做压测,找出 SLO 拐点。
  3. 用队列指标解释瓶颈来自 prefill、decode、KV Cache 还是调度。
  4. 用峰值流量与业务增长预测加入安全系数。
  5. 上线后持续用真实指标修正容量曲线。

适用场景

这套方法特别适合以下场景:

  • 自建 vLLM、Triton、TensorRT-LLM、SGLang 或 Ray Serve 的在线推理平台。
  • 多业务共享同一 GPU 池,需要回答”还能接多少新业务”。
  • 已经出现 P99 TTFT 抬升,但 GPU 利用率解释不了问题。
  • 准备从单模型试点走向多租户生产,需要制定扩容、限流和预算策略。
  • 需要在采购 GPU、选择云实例或规划保底容量前做定量评估。

常见误区

误区一:只看平均 QPS

平均 QPS 会掩盖长尾。LLM 请求的成本由 Token 长度、输出长度、上下文缓存和到达时间共同决定。容量规划至少要看 P50、P95、P99 的输入输出 Token 分布。

误区二:GPU 利用率越高越好

推理服务不是离线训练。在线服务需要为突刺、长尾和失败恢复保留余量。GPU 利用率过高时,队列等待会迅速放大,P99 TTFT 可能先于平均延迟失控。

误区三:autoscaling 可以替代容量规划

Autoscaling 是运行时调节,不是容量规划本身。如果最大副本数、节点池、模型加载时间和 GPU 配额不足,autoscaling 只能更快暴露瓶颈,不能凭空创造容量。

误区四:短 prompt 压测可以代表所有业务

短问答压测通常会高估平台容量。Agent、代码分析、长文档问答、多轮会话和长输出报告都可能显著改变 prefill/decode 比例和 KV Cache 水位。

上线检查清单

指标完整性

上线前确认已经采集以下指标:

  • P50/P95/P99 TTFT
  • P50/P95/P99 request latency
  • P95/P99 request queue time
  • prompt tokens/s 与 generation tokens/s
  • input_tokens、output_tokens 分布
  • running requests、waiting requests
  • KV Cache 使用率
  • GPU 显存、SM、功耗与错误指标
  • 按租户、模型、场景拆分的 SLO 达标率

压测完整性

压测不能只跑一条曲线。至少覆盖低峰、常态、峰值、突刺、长尾和混合流量。每次模型版本、上下文长度、批处理参数、量化方式或硬件规格变化后,都应重新生成容量曲线。

扩容策略

capacity_policy:
  safe_utilization_window: "P99 TTFT 未超过 SLO,queue time 无持续上升"
  scale_up_trigger:
    - "p99_ttft > slo_threshold for 3 windows"
    - "num_requests_waiting 持续增长"
    - "kv_cache_usage_perc > 0.85"
  scale_down_rule:
    cooldown: "10m–30m"
    require_low_queue: true
    require_stable_slo: true
  reserve:
    peak_headroom: "20%–30%"
    failure_headroom: "按节点故障与维修时间单独计算"

发布门禁

新模型或新参数上线前,必须确认:

  • 新版本在相同流量回放下没有降低容量拐点。
  • P99 TTFT 与 queue time 没有显著恶化。
  • 长输入和长输出场景没有挤压短请求体验。
  • 缩容后再扩容不会引入不可接受的冷启动延迟。
  • 限流、降级和排队上限已经配置,并有可观测告警。

FAQ

LLM 容量规划应该多久做一次?

至少在模型版本、上下文长度、推理引擎、量化方式、硬件规格、业务流量结构发生变化时重新做一次。对于增长较快的平台,建议每周或每两周用真实流量刷新容量曲线。

P99 TTFT 和 P99 E2E 延迟哪个更重要?

二者都重要。TTFT 更适合发现入口排队和 prefill 拥塞,E2E 延迟更适合发现长输出和 decode 压力。聊天体验通常优先看 TTFT,报告生成和批量分析则更关注 E2E 与完成率。

没有真实生产流量时怎么压测?

可以先用 synthetic input tokens 和 output tokens 建立粗略曲线,但必须准备几组业务假设:短问答、长文档、长输出、Agent 多轮。上线后要尽快用脱敏后的真实 Token 分布替换合成数据。

参考资料

常见问题

LLM 推理容量规划为什么不能只看 GPU 利用率?
因为同样的 GPU 利用率在短输入、长输入、长输出和 Agent 流量下含义完全不同。容量规划需要同时观察输入 Token、输出 Token、队列等待、TTFT、TPOT 和 KV Cache 水位,才能准确判断 GPU 是否还有余量。
压测时应该用 QPS 还是 Token 吞吐作为主指标?
两者都要看,但 Token 吞吐更接近推理资源消耗的真实成本。QPS 适合描述业务入口容量,而 Token 吞吐、队列水位和尾延迟更适合判断 GPU 是否还有余量以及瓶颈出现在哪个环节。
什么时候需要做 GPU 扩容,而不是只调 autoscaling 参数?
如果压测曲线显示队列等待持续上升、P99 TTFT 超过 SLO、KV Cache 接近上限,且增加副本或调整调度参数无法恢复稳定水位,就应当进入扩容或模型拆分评估流程。