很多 AI Infra 面试题彼此看似独立:计算 KV Cache、解释张量并行、分析 Decode 瓶颈、选择量化方案、设计压测指标、排查 OOM。放到真实部署里,它们其实是同一道综合题的不同步骤。
本文设定一个具体任务:使用 8 张 H100 80GB 部署一个 70B、GQA、BF16 的 Decoder-only 模型,并满足在线聊天业务的延迟目标。我们不会寻找唯一答案,而是展示一套可以复用的决策过程。
图 1:容量规划不是一次显存除法,而是负载、资源、压测、归因和上线门禁构成的闭环。
这里的“容量”不是一个数字,而是一个约束向量:
某个方案可能容纳更多请求,却因为 TPOT 超标而没有更高有效容量;另一个方案可能单请求延迟很低,却因 KV Cache 太小无法承受流量峰值。本文后续所有比较都以 Goodput 为最终尺度,而不是孤立的显存占用或 Tokens/s。
一、需求不能只写“部署 70B”
假设业务提供以下信息:
| 项目 | 假设值 |
|---|---|
| 模型 | 70B Decoder-only,80 层 |
| 隐藏维度 | 8192 |
| Query/KV Heads | 64 / 8 |
| Head Dimension | 128 |
| 权重精度 | BF16 |
| GPU | 8 × H100 80GB,单机 NVLink |
| Prompt P50/P99 | 2K / 16K Token |
| 平均输出 | 500 Token |
| TTFT SLO | P95 小于 2 秒,示例目标 |
| TPOT SLO | P95 小于 60 ms,示例目标 |
这些 SLO 只是演示。真实项目应根据交互产品、离线任务或 Agent 工作流重新定义。
还需要补齐:
- 到达率和峰值并发;
- Prompt 长度的完整分布;
- 系统 Prompt 是否大量重复;
- 是否要求多模型或 Multi-LoRA;
- 单机故障时是否允许降级;
- 成本、功耗和可用区约束。
1.1 从到达率估算活跃请求数
容量规划经常直接假设“并发 64”,却没有解释这个数字来自哪里。稳定系统中可以先用 Little’s Law 建立近似:
是每秒到达请求数, 是请求从进入到完成的平均驻留时间, 是系统中的平均活跃请求数。例如到达率 8 req/s、平均完成时间 6s,平均活跃请求约为 48。突发流量和长尾会让瞬时值更高,因此还需结合 P95/P99 和排队上限。
把并发与业务流量联系起来后,KV Cache 预算才不只是人为选择的压测参数。
二、第一步:权重能否装下
图 2:部署容量规划只使用右侧推理账本,但量化和并行选择仍要明确权重、KV 与运行时空间的边界。
70B BF16 权重的理论大小约为:
使用 TP=8 时,理想情况下每张卡约承担 17.5GB 权重。实际还会包含:
- 未均匀切分或复制的参数;
- CUDA Context;
- NCCL Buffer;
- Attention 和 GEMM Workspace;
- CUDA Graph;
- KV Cache;
- 框架分配器保留空间。
因此,权重能装下不是瓶颈终点,而只是说明 TP=8 在容量上可行。
2.1 是否需要 INT8 或 INT4
如果 BF16 已经为 KV Cache 留出足够空间,量化不一定是第一步。Weight-only 量化可能减少 Decode 读取权重的带宽并提高单机容量,但要确认:
- 目标 GPU 和推理框架是否有成熟 Kernel;
- 模型精度是否满足业务要求;
- Prefill 是否因反量化或 Kernel 形状变慢;
- TP 下量化元数据如何切分;
- 长上下文业务的主要瓶颈究竟是权重还是 KV Cache。
技术选型应该由 Benchmark 决定,而不是由“位宽更低”直接决定。
三、第二步:KV Cache 才是并发上限的关键
KV Cache 每 Token 大小为:
代入 、、、BF16 的 :
即整个模型每个 Token 约 320 KiB KV Cache。
如果 KV Head 能随 TP=8 均匀切分,每卡约承担八分之一,也就是约 40 KiB/Token。具体布局仍应以引擎和 Attention Backend 的实现为准。
3.1 平均负载和最坏负载不同
若 64 个并发请求平均已经缓存 2500 Token,总 KV Cache 约为:
分到 8 张卡约 6.1 GiB/卡,看起来很轻松。
但如果 64 个请求同时接近 16K Prompt,并继续输出 500 Token,总 KV Cache 会超过 300 GiB,单卡分片也可能超过 40 GiB。再考虑权重、Workspace 和运行时空间,容量压力会明显上升。
因此不能用 P50 Prompt 推导最大并发,也不能简单用 P99 长度假设所有请求同时达到最坏值。需要用真实分布做 Trace Replay 或概率模型。
四、第三步:确定并行方式
图 3:本文场景是单机 8 卡,TP 通信位于 NVLink 域;扩展到多机时,应避免把高频 TP Collective 直接放到慢速跨机链路。
单机 8 卡 NVLink 环境下,TP=8 是直观起点:
- 权重均匀分片;
- 层内通信留在高速 NVLink 域;
- 不引入 Pipeline Bubble;
- 一个模型副本可以使用全部 GPU。
但它也有代价:
- 每个 Transformer 层都有 TP 通信;
- 小 Batch 下通信和 Launch 占比可能较高;
- 单个副本占用全部 GPU,故障域较大;
- 扩容粒度是整套 8 卡实例。
如果量化后模型可以用 TP=4,可能在一台 8 卡机器上部署两个副本,以数据并行方式处理不同请求。此时总吞吐、尾延迟和故障隔离可能更好,但单请求可用 KV Cache、单副本最长上下文和量化精度需要重新评估。
所以要比较的不是“TP=4 还是 TP=8 哪个更先进”,而是:
1 | 一个 TP=8 大副本 |
在真实请求分布下,哪个获得更高 Goodput。
五、第四步:配置 KV Cache 与调度器
5.1 gpu_memory_utilization
这个参数决定引擎可以为权重、KV Cache 和运行时使用多少显存。设得太低会限制并发,设得太高则可能在 CUDA Graph、临时 Workspace 或长请求下 OOM。
建议从保守值开始,用压测观察:
- 实际可分配 KV Block 数;
- 峰值显存;
- 抢占次数;
- OOM 和碎片情况。
5.2 max_model_len
如果业务 P99 只有 16K,却把最大序列长度配置为模型理论支持的 128K,可能让引擎为极少出现的请求保留过多规划空间或降低可接纳并发。
更合理的方式是按产品能力设置上限,并为超长请求设计独立队列、限流或专用实例。
5.3 Block Size
- Block 过大:尾块浪费和细粒度调度能力下降;
- Block 过小:块表、哈希和管理开销增加。
不要只测固定长度。不同 Prompt 分布对最佳 Block Size 的偏好可能不同。
六、第五步:哪些功能值得开启
6.1 Prefix Cache
如果大量请求共享系统 Prompt、Few-shot 示例或固定文档前缀,Prefix Cache 可以跳过重复 Prefill,明显降低 TTFT。
如果 Prompt 开头包含随机 ID、时间戳或用户特定内容,Token 前缀很早就分叉,命中率可能很低。此时缓存会占用显存,却没有带来足够收益。
开启前至少统计:
- 可复用前缀长度;
- 请求之间的 Token 级重复率;
- 缓存命中率;
- 命中后节省的 Prefill 时间;
- 缓存块占用和淘汰频率。
6.2 Chunked Prefill
P99 Prompt 达到 16K 时,长 Prefill 很可能干扰正在 Decode 的短请求。Chunked Prefill 可以改善 TPOT 稳定性,但在相同调度预算下可能让长请求 TTFT 增加。
是否开启应由 SLO 决定:
- 聊天业务重视输出流畅度,通常更愿意保护 TPOT;
- 离线批处理只关心吞吐,未必需要同样的切块策略;
- 超长上下文可以进入独立队列,避免污染普通请求。
6.3 CUDA Graph 与 torch.compile
Decode 中 Batch Shape 相对稳定时,CUDA Graph 可以减少 CPU Launch 开销。需要同时评估:
- 捕获 Shape 覆盖范围;
- Graph 额外占用的显存;
- 冷启动时间;
- 动态控制流和调试需求;
- 捕获外算子是否形成新的同步点。
6.4 Speculative Decoding
投机解码使用 Draft 模型或 Self-Draft 结构提出多个候选,再由目标模型并行验证。收益依赖接受率:
- Draft 太弱:候选经常被拒绝;
- Draft 太大:草稿本身开销过高;
- 目标模型 Batch 已经很大:验证收益可能被调度和内存压力抵消。
它更适合作为单独 Benchmark 变量,而不是默认开启。
七、第六步:是否需要 Prefill/Decode 解耦
混合部署时,Prefill 和 Decode 共享 GPU:
- Prefill 偏 Compute Bound;
- Decode 偏 Memory Bound;
- 长 Prefill 会抬高 Decode TPOT;
- 两类阶段的最优 Batch 和并行配置不同。
PD 解耦将它们放在不同 Worker,并通过网络传输 KV Cache。它带来新的成本:
- KV 传输带宽和延迟;
- Worker 比例规划;
- 请求路由;
- 故障恢复;
- KV 一致性和生命周期管理。
只有当混部的相互干扰已经成为主要瓶颈,并且业务规模足以摊销复杂度时,PD 解耦才值得采用。单机 8 卡的第一版系统通常应先把混部调度做好。
八、第七步:设计一套可信 Benchmark
8.1 不要只测固定 Prompt
至少覆盖:
- 短输入、短输出;
- 长输入、短输出;
- 短输入、长输出;
- P99 长上下文;
- 高 Prefix 重复率;
- 无 Prefix 重复;
- 稳态到达和突发流量。
8.2 指标分层
| 层级 | 指标 |
|---|---|
| 用户体验 | TTFT、TPOT、E2E、P95/P99 |
| 系统吞吐 | Request/s、Input/Output Tokens/s |
| SLO | Goodput、超时率、拒绝率 |
| GPU | SM、HBM、显存、Kernel Gap |
| 调度 | Queue Time、Batch Size、抢占次数 |
| Cache | Prefix 命中率、KV Block 使用率 |
8.3 性能回归门禁
每次修改引擎版本、模型权重、CUDA、Attention Backend 或量化方式后,自动执行相同负载集。门禁不应只限制平均吞吐,还应限制:
- P95/P99 TTFT 和 TPOT;
- 峰值显存;
- 错误率和 OOM;
- 输出正确性或精度回归;
- 长上下文稳定性。
九、常见故障如何定位
9.1 启动时 OOM
优先检查权重精度、TP 数量、最大序列长度、CUDA Graph 捕获和显存利用率,而不是直接降低 Batch。
9.2 运行一段时间后 OOM
重点检查 KV Cache 增长、长请求比例、缓存块占用、抢占策略和请求是否正确释放。
9.3 GPU 利用率低
可能原因包括:
- 请求不足,Batch 太小;
- CPU 调度或 Tokenization 跟不上;
- Kernel Launch Gap;
- TP 通信等待;
- 大量小 Kernel;
- 请求长度差异导致调度低效。
先用 Nsight Systems 区分 GPU 空闲和 GPU 内部低效,再决定是否进入 Nsight Compute。
9.4 吞吐很高但用户仍觉得慢
平均 Tokens/s 可能掩盖排队和尾延迟。检查 P99 TTFT、TPOT 和 Goodput,并按 Prompt 长度和并发分桶。
9.5 NCCL Hang
检查所有 Rank 是否按相同顺序进入集合通信、进程是否异常退出、网卡与拓扑是否正确,然后使用 NCCL_DEBUG=INFO 和 nccl-tests 分离代码与基础设施问题。
十、方案决策链与基线配置
一个完整方案不应该只报参数,而应呈现决策链:
1 | 业务负载和 SLO |
对于本文场景,一个合理的第一版基线是:
- 使用 BF16、TP=8 建立正确性和性能基线;
- 使用 PagedAttention 和 Continuous Batching;
- 将最大上下文限制在业务真实需要范围;
- 对 16K 长 Prompt 开启或评估 Chunked Prefill;
- Prefix Cache 由实际前缀命中率决定;
- 用真实请求分布寻找 Token Budget 和并发上限;
- 再与量化后 TP=4、双副本方案比较 Goodput;
- 只有混部干扰无法满足 SLO 时,再评估 PD 解耦。
十一、技术 Q&A
Q1:TP=8 后,70B BF16 权重是否严格变成每卡 17.5GB?
17.5GB 只是参数均匀分片的理论值。Embedding、LM Head、Norm、小参数和量化元数据不一定都按同一方式分片;某些实现还会复制参数,或为集合通信准备连续 Buffer。容量规划应先根据引擎的实际分片规则计算下界,再用模型启动后的逐卡显存数据核对分片不均衡和额外状态。
Q2:为什么不能用 P50 Prompt 长度推导最大并发?
KV Cache 随每个活跃请求的实际缓存长度增长。按 P50 规划会在多个长请求同时出现时低估显存;假设所有请求都是 P99 又可能严重过度配置。更合理的方法是回放真实长度与到达 Trace,或按长度分桶建立概率模型,并为极端长请求设置独立队列、并发上限和 Token 配额。
Q3:Weight-only 量化为什么更可能加速 Decode?
Decode 的 Token 维很小,常受每轮读取大体量权重的 HBM 带宽限制。INT8/INT4 减少权重 Bytes,在具备高效融合反量化 Kernel 时可提高算术强度。Prefill 的大 GEMM 更接近 Compute Bound,其收益取决于低精度 Tensor Core、反量化开销和具体 Shape,因此加速比通常不会简单等于权重压缩比。
Q4:何时应引入 Chunked Prefill 或 PD 解耦,压测结果又如何转化为限流配置?
长 Prefill 阻塞 Decode、导致 TPOT 抖动时,可先用 Chunked Prefill 把计算切片;它会以潜在的 TTFT 增长换取更平滑的 Decode。当混部干扰经过统一调度仍无法满足 SLO,且流量规模足以支撑独立 Worker 池时,才值得用 PD 解耦换取阶段级隔离。压测时应找到满足 TTFT/TPOT SLO 的最高稳定到达率,以单副本 Goodput 乘以安全系数和可用副本数得到服务容量,再按 Prompt 长度或估算 Token 工作量实施 Admission Control;当排队时间、KV Block 水位或 P99 越过拐点时,应排队、拒绝或路由到长上下文池,而不是等到 OOM。
十二、系列导航
上一篇:Softmax 数值稳定性与 IO-Aware Attention
回到开篇:大模型训练与推理的显存模型
十三、参考资料
推理系统
- vLLM:高吞吐 LLM Serving 引擎。
- PagedAttention:KV Cache 分页与内存共享。
- Orca:Iteration-level Scheduling。
- SARATHI:Chunked Prefill。
- DistServe:Prefill/Decode 解耦。
- Fast Inference from Transformers via Speculative Decoding:投机解码。
量化与并行
- SmoothQuant:W8A8 激活平滑量化。
- AWQ:Activation-aware Weight Quantization。
- GPTQ:训练后权重量化。
- Megatron-LM:张量并行。
Benchmark 与指标
- NVIDIA NIM LLM Benchmarking Metrics:TTFT、ITL 和吞吐指标。
- MLPerf Inference:标准化推理 Benchmark。
- GenAI-Perf:生成式模型负载测试。
- vLLM Documentation:引擎参数、Serving 和 Benchmark 工具。
- AIInfraGuide:显存估算、推理引擎、并行部署与性能指标的中文资料,MIT License。