背景问题: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 time 和 TTFT 上——新请求需要等待调度槽、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,很多场景没有简单的闭式答案。
因此,推荐流程是:
- 用粗算模型给出第一版 GPU 数量。
- 用真实 token 分布做压测,找出 SLO 拐点。
- 用队列指标解释瓶颈来自 prefill、decode、KV Cache 还是调度。
- 用峰值流量与业务增长预测加入安全系数。
- 上线后持续用真实指标修正容量曲线。
适用场景
这套方法特别适合以下场景:
- 自建 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 分布替换合成数据。
参考资料
-
NVIDIA Triton Inference Server — GenAI-Perf 文档
https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/perf_analyzer/genai-perf/README.html -
vLLM — Production Metrics
https://docs.vllm.ai/en/latest/usage/metrics/ -
Ray Serve — Autoscaling Guide
https://docs.ray.io/en/latest/serve/autoscaling-guide.html -
Kubernetes — Horizontal Pod Autoscaling
https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/ -
inference-fleet-sim: A Queueing-Theory-Grounded Fleet Capacity Planner for LLM Inference
https://arxiv.org/abs/2603.16054