摘要 一句话答案 先定义模型、精度、上下文、并发和性能目标;再分别计算权重、KV Cache、峰值激活/工作区、运行时预留;最后根据 TP/PP/EP/DP 的切分方式与互联拓扑,把容量下界向上取整到一个可运行、可达到 SLA 的 GPU 配置。
这道题真正考察的不是“会不会用参数量乘 2”,而是能否把以下三件事分开:
- 跑得下:显存容量是否足够。
- 跑得快:算力、HBM 带宽和 GPU 间通信是否足够。
- 跑得稳:在真实请求分布和峰值压力下,是否满足 TTFT、ITL、吞吐与 P99 延迟目标。
0. 面试时先问什么
不要立刻报 GPU 数量。先确认:
- “跑”指的是在线推理、离线推理、LoRA 微调,还是全量训练?
- 模型是 Dense 还是 MoE?总参数、激活参数和模型结构是什么?
- 权重精度、激活精度、KV Cache 精度分别是什么?
- 最大上下文、平均输入长度、平均输出长度和并发是多少?
- 性能目标是什么:吞吐、TTFT、ITL,还是成本优先?
- GPU 型号、单卡显存和互联拓扑是什么?是 PCIe、NVLink/NVSwitch、IB,还是 MNNVL?
注意 推理和训练不能混算 本文主线是 decoder-only LLM 的在线推理。训练还要保存梯度、优化器状态和更多训练激活。以 Adam 为例,朴素混合精度训练仅模型状态就可能达到约 16 bytes/parameter,之后还要加激活;它与推理不是一个数量级的问题。
1. 面试回答模板
1.1 30 秒版本
不能只看参数量。推理显存至少包括四块:模型权重、KV Cache、峰值激活与算子工作区、框架和通信预留。权重由参数量和权重量化精度决定;KV Cache 由层数、KV 头数、head dimension、KV 精度以及所有活跃 token 数决定。GPU 数量还要看 TP/PP/EP 怎么切、DP 是否复制,以及 GPU 间是 PCIe、NVLink 还是跨节点 IB。我的做法是先给出理论容量下界,再留运行空间,最后用目标上下文和并发做实际 profile 和 benchmark。
1.2 2 分钟版本:六步法
- 明确场景:模型结构、推理还是训练、精度、上下文、并发和 SLA。
- 算权重:参数量 × 平均存储字节,再加量化元数据和未量化层。
- 算 KV:每 token 的 K+V 元素数 × KV dtype 字节 × 全部活跃 token。
- 估峰值工作内存:prefill chunk、单轮最大 token、CUDA Graph、NCCL buffer、logits 和临时 workspace。
- 映射并行与拓扑:Dense 常用 TP/PP;MoE 还会使用 EP;DP 增加副本吞吐但一般不降低单副本权重。
- 给出两组数字:最小可跑配置和满足目标 workload/SLA 的建议配置。
提示 面试加分句 显存决定能不能放下,HBM 带宽、计算与互联决定跑得好不好;最少 GPU 数和满足 SLA 的 GPU 数通常不是同一个答案。
2. 统一显存账本
总显存近似为:
$$ M_{total}\approx M_{weights}+M_{KV}+M_{activation/workspace}+M_{runtime}+M_{optional} $$
其中:
- $M_{weights}$:模型权重和量化元数据。
- $M_{KV}$:所有活跃请求的 KV Cache。
- $M_{activation/workspace}$:激活、attention/GEMM 临时空间、prefill 峰值。
- $M_{runtime}$:CUDA context、allocator、CUDA Graph、NCCL、调度器等。
- $M_{optional}$:LoRA、draft model、视觉编码器、额外 cache 等。
说明 单位 GPU 厂商常用十进制 GB;程序日志和手算经常使用 GiB。$1\text{ GiB}=2^{30}$ bytes,$1\text{ GB}=10^9$ bytes。计算时要统一口径。
2.1 权重显存
理论公式:
$$ M_{weights}=P\times\frac{b_w}{8} $$
- $P$:参数量。
- $b_w$:平均每参数位数。
| 权重格式 | 理论字节/参数 | 70B 理论大小 | 说明 |
|---|---|---|---|
| BF16 / FP16 | 2 | 130.4 GiB | 精度稳,容量最大 |
| FP8 / INT8 | 1 | 65.2 GiB | 性能取决于硬件和 kernel |
| INT4 / W4A16 | 0.5 | 32.6 GiB | 还要加 scale、zero-point、padding 等 |
实际值为什么大于理论值:
- 分组量化需要 scale,有些格式还要 zero-point。
- 权重需要 packing 和对齐。
- embedding、norm、lm_head 或敏感层可能保持高精度。
- checkpoint 可能包含额外模块,例如 MTP/draft 权重。
- 引擎加载后的布局不一定等于磁盘文件布局。
因此,更可靠的顺序是:
- 用公式做第一轮估算。
- 查看 checkpoint 实际文件大小和量化配置。
- 以引擎加载后的 profile 为准。
2.2 KV Cache
对普通 decoder-only、每层均使用 attention 的模型:
$$ B_{KV/token}=2\times L\times H_{kv}\times D_{head}\times B_{dtype} $$
其中:
- 2:K 和 V 两份。
- $L$:层数。
- $H_{kv}$:KV heads 数,不是 query heads 数。
- $D_{head}=hidden_size/H_q$。
- $B_{dtype}$:每个 KV 元素的字节数,例如 BF16 为 2,FP8 为 1。
全部 KV Cache:
$$ M_{KV}=B_{KV/token}\times\sum_i T_i $$
$T_i$ 是第 $i$ 个活跃请求已经缓存的 token 数。这里最重要的是所有活跃 token 的总数,而不只是 max_model_len。
哪些结构会改变 KV 公式
- MHA:query heads 和 KV heads 通常相同,KV 最大。
- GQA:多个 query heads 共享一组 K/V,按 $H_{kv}/H_q$ 比例降低 KV。
- MQA:所有 query heads 共享一个 K/V head,KV 更小。
- MLA:保存低维 latent 和额外位置状态,不能直接套普通 GQA 公式。
- Sliding-window/local attention:只保留窗口内或特定层的历史状态。
- Hybrid attention/SSM:不同层的状态类型不同,应逐类计算。
TP 下 KV 是否直接除以 TP
不一定。
- 如果 KV heads 能够被 TP 均匀切分,KV 通常近似按 TP 分片。
- 如果 TP 大于 KV heads,部分实现可能复制 KV heads,而不是继续线性缩小。
- CP、特殊 attention backend、混合模型也会改变切分方式。
所以更准确的说法是:
$$ M_{KV/GPU}\approx\frac{M_{KV}}{S_{KV}} $$
$S_{KV}$ 是实际 KV shard factor,要根据模型结构和引擎实现确认,不能永远假设等于 TP。
2.3 激活和工作区
| 项目 | 主要随什么增长 | 常见控制方法 |
|---|---|---|
| Prefill 激活/临时张量 | 单轮 token 数、hidden size | chunked prefill;降低单轮 token 上限 |
| Attention workspace | backend、序列长度、heads | FlashAttention、FlashInfer、TRT kernel |
| CUDA Graph | capture 的 batch/token buckets | 减少 bucket;缩小 capture 范围;必要时 eager |
| NCCL buffer | TP/EP/PP 与通信算法 | 把细粒度并行放在高速互联域内 |
| Logits/sampling | batch、词表、logprobs | 限制 logprobs 范围和并发 |
| Allocator/碎片 | 动态 shape、进程、运行历史 | 留余量;使用稳定 shape/bucket |
| 附加模型 | draft model、LoRA、视觉编码器 | 单独记账 |
“预留 10%~20%”只能作为初始预算,不能替代 profile。引擎版本、CUDA Graph、kernel、请求 shape 和运行时间都会改变峰值。
3. Attention、FlashAttention 和 Paged Attention
3.1 Prefill 和 Decode 是两种 workload
Prefill:
- 一次处理大量 prompt token。
- GEMM 并行度高,长序列 attention 计算昂贵。
- 普通 dense attention 的计算量随序列长度近似 $O(S^2)$。
- 长 prompt 容易产生激活和 workspace 峰值。
- chunked prefill 能降低峰值,但可能增加调度轮次和 TTFT。
Decode:
- 每轮通常给每条活跃序列生成一个 token。
- 每轮要读取大量权重,并读取历史 KV。
- 低 batch 下经常受 HBM 带宽和 kernel launch 限制。
- 上下文越长,每生成一个 token 要扫描的 KV 越多。
3.2 FlashAttention 到底省什么
FlashAttention 通过 tiling 在片上 SRAM 和 HBM 之间更高效地搬运数据,避免显式物化巨大的 attention score 中间矩阵。
它的关键效果是:
- 显著减少 HBM IO。
- 将 attention 中间内存从二次级别降到近似线性级别。
- 提升实际速度。
但它没有把标准 dense attention 的计算复杂度从 $O(S^2)$ 变成 $O(S)$。
3.3 Paged Attention 到底省什么
Paged Attention 把 KV Cache 按 block/page 管理:
- 减少预分配和内存碎片。
- 允许不同长度请求共享 token pool。
- 便于动态批处理、抢占、复用和换出。
它主要改善的是物理内存管理效率,不会改变一个有效 KV token 的理论字节数。
3.4 Prefix Cache
Prefix cache 保存公共前缀对应的 KV,使后续请求不必重新 prefill。
它可以:
- 降低重复前缀的 TTFT。
- 减少重复计算。
- 提升 agent、多轮对话和长 system prompt 场景的吞吐。
但需要注意:
- 被缓存的 KV 仍然占内存或存储。
- 收益取决于 prefix hit rate。
- 路由不具备 cache affinity 时,命中率会下降。
- 安全隔离场景需要 namespace/salt,避免错误复用。
4. TP / PP / DP / EP / CP
| 并行方式 | 做法 | 容量效果 | 主要通信与代价 | 适用场景 |
|---|---|---|---|---|
| TP | 一层内部切矩阵或 heads | 降低每卡权重,部分 KV/激活也分片 | 每层多次 all-reduce/all-gather | 单机 NVLink/NVSwitch 域优先 |
| PP | 按层切成多个 stage | 权重按 stage 分摊 | stage 间传激活;pipeline bubble | 模型很大或跨节点 |
| DP | 复制模型副本,各自接请求 | 不降低单副本容量 | 在线推理同步较少,但总显存增加 | 扩吞吐、做多副本 |
| EP | 将 MoE experts 分到不同 GPU | 分摊专家权重 | token dispatch/combine,all-to-all | 大 MoE,强依赖互联 |
| CP/SP | 切序列或上下文维度 | 分摊长上下文 KV/激活 | attention 通信与实现复杂 | 超长上下文 |
4.1 TP
TP 适合解决“单层权重太大,一张卡放不下”的问题。
优点:
- 单卡权重下降。
- 同一请求可利用多卡计算。
- 在 NVLink/NVSwitch 域内通常效率较高。
缺点:
- 每层都可能通信。
- 小 batch 或慢互联下,通信占比很高。
- TP 越大,单卡工作越碎,未必线性加速。
4.2 PP
PP 把不同层放在不同 GPU/stage 上。
优点:
- 跨节点时,通信频率通常低于大 TP。
- 对极大模型容易扩展。
缺点:
- pipeline bubble。
- 单请求延迟可能增加。
- 不均匀层或 MoE 层容易产生 stage imbalance。
4.3 DP
普通 DP 是复制整个模型,每个副本处理不同请求。
因此:
- DP 能扩展总吞吐。
- DP 不能解决单个模型副本放不下的问题。
- 对在线推理,DP 副本可配合负载均衡和 KV-aware routing。
4.4 EP
MoE 的 experts 占据大量总参数。EP 把 experts 分到不同 GPU 上。
注意:
- 每个 token 只激活少数 experts,不代表只需要存激活参数对应的权重。
- token 要被 dispatch 到专家所在 GPU,再把结果 combine 回来。
- 通信模式常为 all-to-all,比 dense TP 更容易受到网络和拥塞影响。
- 路由负载不均会形成 straggler。
4.5 拓扑映射原则
- TP 和 EP 是高频、细粒度通信,尽量放在 NVLink/NVSwitch 或 MNNVL 域内。
- 跨节点只有 IB/RoCE 时,优先把 DP 或较粗粒度 PP 放到节点边界。
- 同样 8 张 GPU,8×PCIe 和 8×NVSwitch 的合理并行策略与性能可能差很多。
- “卡数一样”不代表“系统能力一样”。
5. 三个现场实算案例
5.1 Llama 3.1 8B
近似配置:
- 32 layers
- hidden size = 4096
- query heads = 32
- KV heads = 8
- head dimension = 128
BF16 KV 每 token:
$$ 2\times32\times8\times128\times2=131{,}072\text{ bytes}=128\text{ KiB/token} $$
因此,单序列 KV 约为:
| 上下文 | BF16 KV |
|---|---|
| 8K | 1 GiB |
| 32K | 4 GiB |
| 128K | 16 GiB |
权重:
- BF16 8B 理论约 14.9 GiB。
- INT8 理论约 7.45 GiB。
- INT4 理论约 3.73 GiB,再加量化开销。
判断:
- BF16 8B + 单序列 8K 通常能放进 24 GiB GPU。
- BF16 8B + 单序列 32K 可能能放下,但并发和 prefill 峰值受限。
- BF16 8B + 单序列 128K,仅权重和 KV 就约 31 GiB,24 GiB 不可能。
- INT4 降低的是权重;如果 KV 仍为 BF16,长上下文 KV 不会同步缩小。
5.2 Llama 3.1 70B
近似配置:
- 80 layers
- hidden size = 8192
- query heads = 64
- KV heads = 8
- head dimension = 128
BF16 权重理论值:
$$ 70\times10^9\times2/2^{30}\approx130.4\text{ GiB} $$
BF16 KV 每 token:
$$ 2\times80\times8\times128\times2=327{,}680\text{ bytes}=320\text{ KiB/token} $$
单序列 KV:
| 上下文 | BF16 KV,全模型合计 |
|---|---|
| 8K | 2.5 GiB |
| 32K | 10 GiB |
| 128K | 40 GiB |
情况 A:TP=2,2×80 GiB
- 每卡权重约 65.2 GiB。
- 一个 32K 请求,若 KV 完美按 TP=2 分片,每卡 KV 约 5 GiB。
- 权重 + KV 约 70.2 GiB/卡。
- 剩余约 9.8 GiB 给 CUDA context、workspace、CUDA Graph、NCCL 和碎片。
结论:低并发、适当限制 prefill 时可能可跑,但非常紧,需要以真实引擎 profile 为准。
情况 B:TP=2,16 路并发,平均每路 8K 活跃 token
总 KV:
$$ 16\times2.5=40\text{ GiB} $$
按 TP=2 分片后,每卡约 20 GiB KV:
$$ 65.2+20=85.2\text{ GiB/GPU} $$
还没加 workspace 就已经超过 80 GiB,因此不可行。
情况 C:TP=4,4×80 GiB
- 每卡权重约 32.6 GiB。
- 上述 16×8K KV 每卡约 10 GiB。
- 权重 + KV 约 42.6 GiB/卡。
容量明显宽裕,也有更多空间用于更高并发和 prefill 峰值。
重点 结论 “2×80G 能放 BF16 70B 权重”只是权重下界附近,不是通用生产答案。并发、上下文和引擎预留一加入,2×80G 很容易不足。
5.3 MoE:总参数和激活参数分别代表什么
以 DeepSeek-V3 类模型为例,官方资料给出:
- 主模型总参数:671B。
- 每 token 激活参数:约 37B。
两个数字的作用不同:
- 容量预算:如果 experts 不做 offload,通常仍要保存全部 expert 权重,因此主要看总参数和实际 checkpoint。
- 计算预算:每个 token 只经过少量 experts,因此主要计算量更接近激活参数,但仍有共享层、路由、通信和负载不均成本。
常见错误:
| 错误说法 | 更准确的说法 |
|---|---|
| 只激活 37B,所以显存按 37B 算 | 错。常驻专家权重通常按总参数或实际分片计算 |
| 671B,所以每 token 都算 671B | 错。每 token 只走少数 experts |
| 加 EP 就能线性扩展 | 未必。all-to-all、负载偏斜和跨节点拓扑都会降低效率 |
6. 从公式得到 GPU 数量
6.1 容量下界
假设每卡容量为 $C$,希望使用的安全比例为 $u$:
$$ M_{budget/GPU}=C\times u $$
需要满足:
$$ M_{weights/GPU}+M_{KV/GPU}+M_{workspace/GPU}+M_{runtime/GPU}<M_{budget/GPU} $$
然后把 GPU 数向上取整到一个模型和 kernel 支持的 TP/PP/EP 组合。
注意:不同引擎的“利用率”参数口径不同。有的控制整个 executor,有的控制权重 + KV 静态池,有的只按加载权重和 buffer 后的剩余显存给 KV 分配。不能把同一个 0.9 在三套引擎间机械照搬。
6.2 性能下界
容量可行后,还要问:这些 GPU 能否达到性能目标?
Decode 粗略带宽视角
低 batch 下,每生成一轮需要读取大量权重,decode 常受 HBM 带宽限制。
一个非常粗的下界:
$$ t_{decode\ step}\gtrsim\frac{bytes\ read\ per\ step}{effective\ HBM\ bandwidth} $$
batch 增大后,相同权重读取可以服务更多 token,算术强度提高,但 KV、激活和调度压力也会上升。
Prefill 粗略计算视角
- 大量 GEMM,通常更容易利用 Tensor Core。
- dense attention 随上下文增长很快。
- TTFT 还包括排队、tokenization、调度和通信。
通信视角
- TP:几乎每层都可能发生 collective。
- EP:token all-to-all。
- PP:stage 间传激活并有 bubble。
- 跨慢链路切得太细,加 GPU 反而可能更慢。
6.3 正确答案应该包含两个数字
例如:
最小可跑需要 2×80 GiB;但对于最大 32K、平均 8K 活跃 token、并发 16,并且有明确 P99 TTFT/ITL 目标的在线服务,我会从 4×80 GiB 开始压测,再根据 KV 利用率和吞吐调整。
7. vLLM / SGLang / TensorRT-LLM 参数地图
注意 版本提醒 这些项目变化很快,默认值可能随版本改变。下面重点记录参数的控制对象。实际部署时以当前安装版本的
--help和对应版本文档为准。
7.1 vLLM
| 参数 | 控制什么 | 注意事项 |
|---|---|---|
--gpu-memory-utilization |
当前 executor 实例的 GPU 显存预算 | 默认值曾为 0.9,较新配置可能不同;查当前版本 |
--kv-cache-memory-bytes |
每 GPU KV Cache 的精确字节预算 | 设置后会覆盖基于 utilization 的自动推导 |
--kv-cache-dtype |
KV Cache 精度 | FP8 可近似将 KV 减半,但要验证 scale 和精度 |
--max-num-batched-tokens |
单轮最多处理 token 数 | 影响 prefill 峰值、调度和吞吐 |
--max-num-seqs |
单轮最大序列数 | 限制并发和 CUDA Graph shape |
--cpu-offload-gb |
权重 CPU offload | 每次 forward 都会搬权重,互联慢时非常昂贵 |
--kv-offloading-size |
KV Cache 的 CPU offload buffer | 新版本可使用 native 或 LMCache backend |
--enable-prefix-caching |
前缀 KV 复用 | 收益取决于前缀命中率 |
理解重点:
- vLLM 启动时会 profile 非 KV 开销,再把预算中的剩余部分用于 KV blocks。
- 启动日志中可用 KV token capacity 比仅看
max_model_len更有价值。 max_num_batched_tokens主要影响一次迭代的工作量,不等于 KV 总容量。
7.2 SGLang
| 参数 | 控制什么 | 注意事项 |
|---|---|---|
--mem-fraction-static |
模型权重 + KV 静态池占 GPU 显存的比例 | OOM 时降低,但 KV token pool 和并发也会下降 |
--max-total-tokens |
KV 内存池可容纳的总 token 数 | 比“最大上下文”更接近总并发容量 |
--max-running-requests |
最大运行请求数 | decode OOM 时可降低 |
--chunked-prefill-size |
prefill 的 chunk 大小 | 长 prompt prefill OOM 时优先降低 |
--max-prefill-tokens |
prefill admission 上限 | 控制峰值工作量 |
--kv-cache-dtype |
KV Cache 精度 | FP8 需要验证 scale 和质量 |
--tp-size / --ep-size |
TP / EP 并行度 | 要结合 GPU 拓扑 |
SGLang 的 RadixAttention 用于复用前缀 KV;HiCache 将缓存扩展为 GPU、CPU 和存储多层。
7.3 TensorRT-LLM
| 参数 | 控制什么 | 注意事项 |
|---|---|---|
free_gpu_memory_fraction |
权重和 buffer 加载后,剩余显存中分给 KV 的比例 | 文档常见默认 0.9;不是总显存的 90% |
max_tokens |
KV Cache 最大 token 数 | 与 fraction 同时设置时取更小容量 |
max_num_tokens |
一次迭代/engine shape 的 token 上限 | 影响 activation/workspace;具体口径看 API |
kv_cache_config.dtype |
KV Cache dtype | 可选 BF16/FP16/FP8 等,依硬件与 backend |
enable_block_reuse |
跨请求 KV block 复用 | 生产上要考虑 cache salt/隔离 |
host_cache_size |
host KV cache 容量 | 需要足够快的 host link 和预取策略 |
tensor_parallel_size / pipeline_parallel_size / moe_expert_parallel_size |
并行切分 | 通信必须映射到合适拓扑 |
7.4 容易被漏掉的软件 buffer
- CUDA context 和库初始化。
- CUDA Graph capture buckets。
- NCCL communicator 和通信 buffer。
- Attention/GEMM workspace。
- 请求输入输出和 sampling buffer。
- 全词表 logits、logprobs。
- Prefix cache 的 page 和元数据。
- Scheduler bookkeeping。
- 量化 scale 和临时反量化空间。
- LoRA adapters。
- Speculative decoding 的 draft model、draft KV、verify workspace。
- 多模态模型的视觉编码器和图像 embedding。
8. KV Cache offload
8.1 分层结构
可以把 KV Cache 看成一个存储层级:
GPU HBM(热 KV,最低延迟)
↓ evict / prefetch
CPU DRAM(容量层)
↓
本地 NVMe(冷层)
↓
远端 KV Store / 分布式存储(跨实例共享)
| 层级 | 优点 | 瓶颈 | 典型组件/路径 |
|---|---|---|---|
| GPU HBM | 最低延迟、最高带宽 | 容量贵且有限 | Paged KV、Radix cache、TRT KV manager |
| CPU DRAM | 容量大、成本低 | PCIe/C2C、NUMA | vLLM native/LMCache、SGLang HiCache、TRT host cache |
| 本地 NVMe | 容量更大 | 延迟和吞吐远低于 HBM | LMCache、HiCache storage backend |
| 远端 KV/存储 | 跨实例共享、容量解耦 | 网络、路由、一致性、P99 | LMCache、Mooncake、NIXL、Dynamo 生态 |
8.2 权重 offload 和 KV offload 的区别
权重 offload:
- 每层、每次 forward 都可能需要把权重搬回 GPU。
- decode 时会形成持续的数据搬运。
- 经 PCIe 时很容易成为主瓶颈。
KV offload:
- 可以只换出暂时不活跃的 page。
- 如果请求恢复前能异步预取,代价可能更可控。
- 如果活跃长上下文每个 decode step 都频繁缺页,性能仍会迅速恶化。
8.3 Offload 的量纲分析
最低传输时间:
$$ t_{transfer}\ge\frac{bytes\ to\ move}{effective\ link\ bandwidth} $$
例如要从 CPU 搬 10 GiB KV:
- 有效带宽 32 GB/s:纯传输下界约 0.31 秒。
- 有效带宽 400 GB/s:纯传输下界约 25 毫秒。
真实时间还要加入:
- 协议和软件开销。
- NUMA 路径。
- 并发流量和链路争用。
- page lookup、序列化和调度。
- 是否可以和计算重叠。
8.4 相关组件
- LMCache:与 vLLM 等引擎连接,将 KV 扩展到 CPU、磁盘或远端层。
- SGLang HiCache:GPU、CPU、storage 多级 KV cache。
- Mooncake:面向分布式 KV/传输与服务解耦的组件生态。
- NIXL:为 GPU/CPU/存储间数据传输提供抽象和优化路径。
- NVIDIA Dynamo:可做 KV-aware routing、prefill/decode disaggregation 和多实例编排。
- TensorRT-LLM KV Cache Manager:block reuse、host cache、优先级淘汰等。
8.5 是否值得 offload:四个问题
- 前缀命中率和未来复用率有多高?
- 一次恢复需要搬多少 GiB?
- 传输能否与计算重叠,是否有异步 prefetch?
- 路由是否 KV-aware,能否把请求送回拥有 cache 的实例?
9. PCIe / NVLink / NVSwitch / IB / C2C / MNNVL
| 互联 | 连接对象 | 主要角色 | 对推理并行的意义 |
|---|---|---|---|
| PCIe | GPU↔CPU,或无 NVLink 时 GPU↔GPU | 通用 I/O 和 fallback P2P | TP/EP 容易受通信限制 |
| NVLink | GPU↔GPU | 高带宽低延迟 P2P | 适合单机 TP/EP |
| NVSwitch | 多 GPU 交换网络 | 构建高双截面 NVLink 域 | 8 卡 HGX/DGX 内适合较大 TP |
| InfiniBand | 跨服务器 NIC/GPU RDMA | 集群 scale-out | 常用于跨节点 DP/PP;大 TP/EP 需强网络 |
| NVLink-C2C | Grace CPU↔Hopper/Blackwell GPU | 一致性高带宽 CPU-GPU 互联 | 有利于 CPU 内存扩展与 offload |
| MNNVL | 跨 OS 节点的 rack-scale NVLink 域 | Blackwell NVL72 等 scale-up fabric | 让多节点 GPU 处于更大的 NVLink 域 |
9.1 PCIe
- 通用、普遍存在。
- CPU offload 和无 NVLink 的 GPU P2P 依赖它。
- 单向有效带宽通常只有几十 GB/s 量级,远低于 HBM。
- 要注意 CPU socket、NUMA 和 PCIe switch 拓扑。
9.2 NVLink / NVSwitch
- NVLink 是 GPU 间高速链路。
- NVSwitch 将多张 GPU 连接成高双截面的交换网络。
- H100 官方资料给出第四代 NVLink 每 GPU 最高 900 GB/s aggregate GPU-to-GPU bandwidth。
- 具体比较时要确认是单向、双向还是 aggregate 口径。
9.3 InfiniBand
- 用于跨节点扩展。
- NDR 400 Gb/s 单端口线速约 50 GB/s,实际有效带宽还要扣除协议和系统开销。
- GPUDirect RDMA 可减少 CPU 中转。
- 网络拓扑、rail 数、NCCL 配置和拥塞会影响实际性能。
9.4 NVLink-C2C
NVLink-C2C 主要连接 Grace CPU 与 Hopper/Blackwell GPU:
- 提供高带宽、内存一致性的 CPU-GPU 访问。
- 适合统一内存和 CPU memory oversubscription/offload。
- 它不是普通意义上用于 GPU collective 的 GPU-GPU NVLink。
9.5 MNNVL
官方常用缩写是 MNNVL(Multi-Node NVLink)。
- 跨多个 OS 节点建立 rack-scale NVLink domain。
- GB200 NVL72 将 72 张 GPU 放入一个 NVLink 域。
- NVIDIA 官方资料给出第五代 NVLink 每 GPU 1.8 TB/s,整架约 130 TB/s aggregate。
- 依赖 Fabric Manager、IMEX、NCCL 等系统软件正确配置。
提示 面试表达 Scale-up 解决“一个模型副本内部怎样高速协同”,典型是 NVLink/NVSwitch/MNNVL;scale-out 解决“更多节点和副本怎样扩展”,典型是 InfiniBand/RoCE。二者的并行映射不同。
10. 从理论估算到生产压测
10.1 完整流程
- 固定模型 revision、量化 checkpoint、driver/CUDA、引擎版本和 attention backend。
- 读取模型配置:layers、hidden size、query heads、KV heads、head dimension、attention 类型、MoE experts/top-k。
- 按实际 checkpoint 和加载 profile 校准权重。
- 从真实请求日志获取 input/output length、活跃 token、并发和 prefix 重复率分布。
- 计算理论权重和 KV,得到最小卡数与初始并行方案。
- 启动引擎,记录每卡权重、非 KV 显存和可用 KV token capacity。
- 分别压测 prefill-heavy、decode-heavy、长上下文、突发流量和混合请求。
- 记录 TTFT、ITL、throughput、排队时间、preemption/recompute、cache hit 和峰值显存。
- 做单卡、单机多卡、跨节点对照,确认 NCCL 实际使用预期链路。
- 做 30~60 分钟稳态压测,观察碎片、热身、graph capture 和异常请求。
10.2 应该记录的指标
| 类别 | 指标 |
|---|---|
| 容量 | 每卡权重、非 KV 占用、KV token capacity、峰值显存 |
| 延迟 | TTFT P50/P95/P99、ITL P50/P95/P99、端到端延迟 |
| 吞吐 | input tokens/s、output tokens/s、requests/s |
| 调度 | queue time、running/queued requests、preemption、recompute |
| Cache | prefix hit rate、GPU/CPU/storage hit、eviction、prefetch |
| 通信 | NCCL algorithm、NVLink/IB 利用率、all-reduce/all-to-all 时间 |
| 稳定性 | OOM、碎片增长、错误率、长尾请求、性能漂移 |
10.3 记录模板
model:
revision:
weight_quantization:
kv_cache_dtype:
engine_and_version:
attention_backend:
gpu_model:
gpu_count:
topology:
tp:
pp:
dp:
ep:
cp:
max_model_len:
kv_token_capacity:
max_num_batched_tokens:
max_running_requests:
input_length_p50_p95_max:
output_length_p50_p95_max:
concurrency:
arrival_rate:
peak_memory_per_gpu:
ttft_p50_p99:
itl_p50_p99:
input_tokens_per_second:
output_tokens_per_second:
prefix_cache_hit_rate:
preemption_or_recompute:
11. 常见追问
为什么 4-bit 模型不一定快 4 倍?
因为性能瓶颈可能是:
- 反量化和 kernel 效率。
- 激活或 KV Cache。
- 小 batch 下的 kernel launch。
- TP/EP 通信。
- GPU 对某种 INT4 格式没有高效原生支持。
量化首先降低的是权重容量和权重带宽,不保证端到端线性加速。
为什么 max context 不能直接代表并发?
KV 消耗由所有活跃 token 的总数决定。一个 128K 请求和 16 个 8K 请求的 KV 总量可能相似,但 prefill、调度、延迟和 page 碎片行为不同。
FlashAttention 是否把 attention 变成线性复杂度?
它把中间内存和 HBM IO 显著优化,dense attention 的计算量仍近似 $O(S^2)$。
DP 能否解决模型放不下?
普通 DP 复制模型,不能降低单副本权重。模型放不下要使用 TP、PP、EP、量化或 offload。
为什么 MoE 对网络要求高?
EP 后 token 需要 dispatch 到 expert 所在 GPU,再把结果 combine;这是 all-to-all 通信,而且路由不均会造成部分 GPU 成为 straggler。
为什么只知道 GPU 型号还不够?
同一型号可能有:
- 不同显存容量。
- PCIe 与 SXM 版本。
- 是否有 NVLink/NVSwitch。
- 不同 CPU/NUMA/PCIe 拓扑。
- 不同跨节点 IB/RoCE 配置。
12. 一页速查
| 要问 | 要算 | 要验证 |
|---|---|---|
| Dense 还是 MoE | 权重:$P\times bits/8$ + 量化开销 | 加载后每卡权重 |
| 推理还是训练 | KV:$2LH_{kv}D\times bytes\times tokens$ | KV token capacity |
| 权重/KV/激活精度 | workspace:按单轮 token 峰值 | prefill 峰值显存 |
| 最大/平均上下文与并发 | 并行后每卡分片与复制 | TTFT、ITL、throughput |
| 请求分布和 SLA | offload:bytes/bandwidth | cache hit、preemption |
| GPU 容量和拓扑 | 通信量和有效链路带宽 | NCCL 是否走预期链路 |
13. 可直接背诵的完整回答
我会先澄清这里的“跑”指在线推理、离线推理还是训练。若是在线推理,GPU 数没有只由参数量决定的唯一答案,我会先定义模型结构、权重和 KV 精度、最大与平均上下文、并发、目标吞吐和延迟。
容量上我分四块记账。第一是权重,约等于参数量乘以每参数字节数,但量化还要加 scale、zero-point 和未量化层。第二是 KV Cache,普通 decoder 模型每 token 约为 2×层数×KV 头数×head dimension×KV dtype 字节数,再乘所有活跃 token。第三是 prefill 激活、attention/GEMM workspace、CUDA Graph 和通信 buffer。第四是框架、分配器碎片,以及 draft model、LoRA 或视觉编码器等附加项。
然后看并行。Dense 模型通常用 TP/PP 切权重,DP 是复制副本、主要扩吞吐;MoE 用 EP 切专家,但会引入 all-to-all。TP/EP 应尽量放在 NVLink/NVSwitch 或 MNNVL 域内,跨节点 IB 更适合 DP 或较粗粒度 PP,具体仍需 benchmark。
最后我会给两个数字:理论最小可跑 GPU 数,以及在给定长度分布、并发和 P99 SLA 下的生产建议 GPU 数。比如 BF16 70B 权重约 130 GiB,2×80G 只是权重下界附近;当 16 路请求平均各有 8K 活跃 token 时,BF16 KV 总计约 40 GiB,再加 workspace,TP=2 就放不下,而 TP=4 会更合理。
14. 资料来源
推理引擎
- vLLM Serve CLI
- vLLM Config API:KV memory 与 offloading
- SGLang Server Arguments
- SGLang HiCache
- TensorRT-LLM Memory Usage
- TensorRT-LLM KV Cache System
模型与算法
NVIDIA 硬件与互联
- NVIDIA H100
- NVIDIA Multi-Node NVLink Systems
- NVIDIA MNNVL User Guide
- NCCL MNNVL 配置
- NVIDIA GB200 NVL72
说明 引擎参数和默认值更新很快。本文的长期价值在于显存账本、KV 公式、并行通信和验证方法;具体参数默认值应在实际部署时重新确认。
Concept supplement
对几个易混概念的进一步解释
MHA 是切片还是复制 hidden state?
都不是。完整 hidden state 分别通过可学习的 WQ、WK、WV 投影;投影结果再 reshape 成多个 heads。每个 head 可以看见完整输入,只是学习了不同的投影子空间。实现中常把多个 head 的小矩阵合并成一个大矩阵,一次 GEMM 后再 reshape。
为什么常见 Dhead = hidden_size / Hq?
更一般的公式是 Dhead = Q projection 总输出宽度 / Hq。只有架构选择 Hq·Dhead = Dmodel 时,才简化为 hidden_size/Hq。Dhead 可以自定义;此时 WQ 的输出宽度与 Wo 的输入宽度会相应改变。Q 和 K 要做点积,所以通常要求 Dq=Dk;Dv 理论上可以不同。
GEMM 的复杂度在 CPU 和 GPU 上是否不同?
矩阵 [M,K]×[K,N] 的算术工作量在任何硬件上都约为 2MNK FLOPs。GPU 改变的是并行执行时间、Tensor Core 利用率和数据搬运效率,而不是工作量本身。固定硬件上,当矩阵足够大并已饱和,序列长度翻倍仍会让 dense attention 的主要 FLOPs 接近四倍;小 shape 下则可能因为利用率变化而不严格呈现四倍 wall time。