LLM 推理系统全栈综合分析
0. 阅读指南
这是一篇 synthesis page,把 LLM 推理子目录下 6 篇文章 + GPU Communication 1 篇文章拉通成一张全栈视图。每一节都会用相对路径反向链接到对应的源页面,建议把本页当成「目录 + 论证」,把源页当成「细节 + 公式」。
阅读路径建议:
- 第一次读 → 概述 + 全栈地图(§1、§2)
- 想精读某一层 → 跳到 §3 对应小节,再点链接进源页
- 关心相互作用 → §4 技术协同/冲突矩阵
- 做选型 → §5 引擎对照 + §6 决策树
1. 核心瓶颈:一切优化的起点
1.1 推理的两阶段非对称
LLM 推理可以拆成两个性质截然不同的阶段,这是理解所有后续优化的基础(详见 Compute-bound vs Memory-bound):
Prefill (处理 prompt) Decode (逐 token 生成)
──────────────────── ──────────────────────
输入: [batch, seq, hidden] 输入: [batch, 1, hidden]
矩阵: GEMM 矩阵: GEMV
算术强度: ~2048 FLOPs/Byte 算术强度: ~1 FLOPs/Byte
瓶颈: TFLOPS (算力) 瓶颈: HBM 带宽
吞吐 ∝ GPU 算力 吞吐 ∝ 显存带宽 / 模型大小
一句话:prefill 像训练(compute-bound),decode 像内存拷贝(memory-bound)。这条认知贯穿后面所有优化技术——它们要么减少 decode 要搬的数据(量化、GQA、MLA),要么把 decode 的访存摊薄到多个请求(batching),要么把 decode 一次出多个 token 摊薄访存(speculative decoding),要么把两阶段拆开独立扩缩容(P/D 分离)。
1.2 三条物理天花板
任何工程优化都不可能突破物理上限,先把天花板画清楚:
| 天花板 | 公式 | 受限于 | A100 / H100 实际值 |
|---|---|---|---|
| Decode 单请求下限 | params × bytes / HBM_BW | HBM 带宽 | 8B/FP16: 8 ms (A100) / 4.8 ms (H100) |
| Prefill 下限 | 2 × params × tokens / TFLOPS | Tensor Core 算力 | 8B/2048t: 105 ms (A100) / 33 ms (H100) |
| 多卡通信下限 | data / NVLink_BW | NVLink/NVSwitch/IB | 900 GB/s (NVLink 4.0) |
这三条线对应 02-compute-vs-memory-bound §3.3 的 decode 下限、02 §2.2 的 prefill 公式,以及 GPU Communication §1.3 的 NVLink 带宽演进。
1.3 KV Cache —— OOM 的头号嫌犯
decode 的 memory-bound 性质让我们想增大 batch,但 batch 一增 KV Cache 就爆炸。一个 token 在一层中的 KV Cache 大小由 KV Cache §2 给出:
KV Cache = 2 × layers × kv_heads × head_dim × seq_len × batch × bytes
Llama-3-8B / MHA / FP16 / seq=2048:单请求就 1 GB;batch=32 → 32 GB,把 A100-40GB 直接打爆。这就是为什么后面的优化必须层层接力。
2. 全栈优化地图
2.1 层次划分
graph TB
subgraph L7["L7: 服务层 / API"]
SVC["OpenAI 兼容接口 · 多租户 · 限流"]
end
subgraph L6["L6: 引擎层"]
ENG["vLLM · TensorRT-LLM · SGLang · llama.cpp"]
end
subgraph L5["L5: 调度层"]
SCH["Continuous Batching · Chunked Prefill · P/D 分离 · Preemption"]
end
subgraph L4["L4: 内存管理层"]
MEM["PagedAttention · RadixAttention · Prefix CoW · KV Swap"]
end
subgraph L3["L3: 算法层"]
ALG["GQA/MLA · 量化 (INT4/INT8/FP8) · Speculative Decoding · Sliding Window"]
end
subgraph L2["L2: Kernel 层"]
KER["FlashAttention · FlashDecode · Kernel Fusion · 自定义 CUDA"]
end
subgraph L1["L1: 硬件层"]
HW["HBM · SRAM · Tensor Core · NVLink/NVSwitch · GPUDirect RDMA"]
end
L7 --> L6 --> L5 --> L4 --> L3 --> L2 --> L1
2.2 优化技术 × 层次映射表
| 技术 | 主要层 | 主要瓶颈对应 | 源页面 |
|---|---|---|---|
| HBM 带宽 / SRAM 容量 | L1 | Decode memory-bound 物理上限 | 02 |
| NVLink / NVSwitch | L1 | TP 跨卡通信 | GPU Comm |
| GPUDirect RDMA | L1 | 跨节点 KV 传输、P/D 分离 | GPU Comm |
| FlashAttention | L2 | Prefill attention 的 O(N²) HBM 访问 | 06 |
| FlashDecode | L2 | Decode attention 并行度不足 | 06 |
| Kernel Fusion | L2 | LayerNorm / GELU / Linear 间反复读写 HBM | 06 |
| MHA → GQA → MLA | L3 | KV Cache 体积 | 01 |
| 权重量化 (GPTQ/AWQ) | L3 | Decode 权重搬运量 | 03 |
| KV Cache 量化 | L3 | KV 读取带宽 | 01 03 |
| Speculative Decoding | L3 | Decode 自回归串行 | 05 |
| Sliding Window / H2O / StreamingLLM | L3 | 长上下文 KV 爆炸 | 01 |
| PagedAttention | L4 | KV Cache 碎片、利用率 30% | 01 |
| RadixAttention | L4 | 多轮对话/Agent 前缀重复计算 | 06 |
| Prefix CoW 共享 | L4 | 大量请求共享 system prompt | 01 |
| Continuous Batching | L5 | 静态 batch 木桶效应、GPU 利用率 | 04 |
| Chunked Prefill | L5 | Prefill 阻塞 decode、ITL 抖动 | 04 |
| P/D 分离 | L5 | 两阶段硬件需求不同 | 04 |
| Preemption / KV Swap | L5 | OOM 时如何不丢请求 | 04 |
| TP / PP / EP | L5+L1 | 模型放不进单卡 | 06 |
2.3 一张图看懂「优化打在哪个瓶颈上」
┌─────────────────────────────────────────────────────────────┐
│ Prefill (Compute-bound) Decode (Memory-bound) │
├─────────────────────────────────────────────────────────────┤
│ 算力 ↑ FlashAttention │
│ Kernel Fusion │
│ FP8 Tensor Core Speculative Decoding │
│ Chunked Prefill ─┐ (把 decode 变成 prefill)│
│ ↓ │
│ 带宽 ↓ ←─────────── 量化 (INT4/INT8/FP8) │
│ GQA / MLA │
│ KV Cache 量化 │
│ FlashDecode │
│ Continuous Batching │
│ (摊薄权重访存) │
│ │
│ 容量 ↓ PagedAttention (KV 利用率 ↑) │
│ Sliding Window / StreamingLLM │
│ Prefix CoW / RadixAttention │
│ │
│ 互联 ↓ NVLink / NVSwitch (TP) │
│ GPUDirect RDMA (P/D 分离、跨节点) │
└─────────────────────────────────────────────────────────────┘
3. 各层优化技术综述
3.1 L1 硬件层:HBM、SRAM 与互联
3.1.1 内存层次决定 attention 的写法
GPU 的 SRAM 带宽是 HBM 的 ~10×(详见 06 §2.1),但容量只有 ~20 MB。这两个数字直接决定了 attention kernel 必须做 tiling——把 seq_len × seq_len 的中间矩阵留在 SRAM 里,永远别写回 HBM。
SRAM: ~20 MB, ~19 TB/s ← FlashAttention 工作区
HBM: 80 GB, 2-3 TB/s ← KV Cache + 权重 + 激活
NVLink: 900 GB/s (NVLink 4.0) ← 跨 GPU
PCIe: ~64 GB/s (PCIe 5) ← GPU↔CPU、GPU↔NIC
IB: 400 Gbps (~50 GB/s) ← 跨节点
3.1.2 NVLink / NVSwitch:Tensor Parallel 的物理基础
GPU Communication §1-2 详细讲了 NVLink 1.0→4.0 从 80 GB/s 跃迁到 900 GB/s 的过程,以及 NVSwitch 如何在单节点内实现 8/16 卡全互联。这条线和 Tensor Parallel (06 §4.1) 的耦合极强:
- TP 每层都要 AllReduce 一次(hidden_dim × seq_len 量级),没有 NVLink 直接掉一半性能
- PP 只在层边界传激活,对带宽要求低,所以 PP 能跨节点,TP 通常不跨节点
3.1.3 GPUDirect RDMA:P/D 分离的命门
P/D 分离架构 (04 §5.3) 要求 Prefill 节点把生成的 KV Cache 传给 Decode 节点。一条 32K 长 prompt 的 KV Cache 可以达到 GB 级,没有 GPUDirect RDMA(零拷贝、Kernel Bypass、GPU↔NIC 直通),这一步就成为新瓶颈。这是为什么 Mooncake、DistServe 都强依赖 InfiniBand + GDR。
3.2 L2 Kernel 层:让 GPU 别在等数据
3.2.1 FlashAttention:把 attention 留在 SRAM
详见 06 §2.1。核心三件事:
- Tiling —— 把 Q/K/V 切成能塞进 SRAM 的小块
- Online softmax —— 边算边维护 max/sum,不需要把完整 score 矩阵物化
- 不写中间矩阵 ——
seq²的中间结果永远不落 HBM
效果:内存 O(seq²) → O(seq),prefill attention 加速 2-4×,序列越长越爽。
3.2.2 FlashDecode:Decode 阶段的小 Q 问题
Decode 时 Q.shape = [1, heads, dim],标准 FlashAttention 的 tiling 是按 Q 维切的——Q 太小,GPU 大部分 SM 闲着。FlashDecode 的做法(06 §2.2):
1. 按 KV 的 seq_len 维度切多个 split
2. 每个 split 独立算 partial attention(GPU SM 全部用起来)
3. 用 online softmax 把多个 partial 结果合并
效果:decode attention 加速 2-8×,长上下文越长越明显。
3.2.3 Kernel Fusion:消灭中间结果
LayerNorm → Linear → GELU 三个 op 如果各自启动一个 kernel,每个都要从 HBM 读、写一次。融合成一个 kernel 后,中间结果留在寄存器/SRAM,HBM 流量大幅下降。TensorRT-LLM 的 Kernel Fusion 是最激进的(06 §3.2),代价是模型支持要写成图编译形式。
3.3 L3 算法层:从根上减少 KV / 权重 / 串行性
3.3.1 KV Cache 减体积三连:MHA → GQA → MLA
这是过去三年模型架构演进的一条主线(01 §2.4-2.6):
| 机制 | KV/token/层 | 相对 MHA | 代表模型 |
|---|---|---|---|
| MHA | 2 × n_h × d_h | 1× | GPT-3, Llama-1 |
| GQA (8 groups) | 2 × n_g × d_h | 1/8 | Llama-2/3-70B, Mistral, Qwen |
| MQA | 2 × d_h | 1/128 | PaLM, Falcon |
| MLA | d_c + d_h^R | 1/57 | DeepSeek-V2/V3 |
GQA 减「头数」,MLA 减「每个 token 的总 KV 维度」(把所有 head 的 K/V 联合压到一个低维潜向量,推理时矩阵吸收,详见 01 §2.6)。MLA 是目前 KV Cache 最激进的压缩思路,DeepSeek-V2 报告减少 93.3% 且质量更好。
3.3.2 量化:让 decode 直接快 2-4×
详见 量化。一句话:decode 是 memory-bound,搬的数据少一半,速度就翻一倍。
Llama-3-8B decode 单 token:
FP16: 16 GB / 2 TB/s = 8 ms
INT8: 8 GB / 2 TB/s = 4 ms ← 2×
INT4: 4 GB / 2 TB/s = 2 ms ← 4×
主流方法的差异在「精度」和「kernel 生态」:
| 方法 | 精度 | GPU 推理 | CPU 推理 | 适用 |
|---|---|---|---|---|
| GPTQ | INT4/3/2 | 优秀 (Marlin) | × | GPU 服务端 |
| AWQ | INT4 | 优秀 | × | GPU 服务端 |
| GGUF | Q2-Q8 | 良好 | 支持 | 本地/边缘/混合 |
| BitsAndBytes | INT8/INT4 | 良好 | × | 快速实验 / QLoRA |
| FP8 | FP8 | 最优 (H100 原生 Tensor Core) | × | H100/H200 生产 |
FP8 是 H100 时代的事实标准——它有原生 Tensor Core 加速,精度几乎无损失,所以新模型部署默认从 FP8 起步。
3.3.3 KV Cache 量化:另一个被忽视的杠杆
权重量化大家都谈,但 KV Cache 量化(FP16 → INT8/FP8 → INT4)同样直接影响 decode 带宽(01 §4.2、03 §1.2)。在长上下文场景下,KV Cache 可能比权重还大,KV 量化对长 context 尤其重要。vLLM 和 TensorRT-LLM 都支持。
3.3.4 Speculative Decoding:打破「一次一个」
详见 投机解码。它的精妙之处在于输出分布数学上完全等于直接用 target 模型采样(speculative sampling 的拒绝重采样保证),所以叫「无损加速」。
传统: 4 次 70B forward → 4 个 token
投机: 5 次 1B forward + 1 次 70B forward → 4 个 token (典型情况)
小模型 forward 时间可忽略,加速 ~4×
它的本质(也是 05 §6 的核心洞察)是:把 memory-bound 的 decode 转化为 compute-bound 的 verification——一次验证 K 个 token 是一次小型 prefill,算术强度从 1 提到 K。
主流变体:
| 方法 | 额外参数 | 训练 | 加速 |
|---|---|---|---|
| Draft Model (独立小模型) | 完整 | 否 | 1.5-2.5× |
| EAGLE-2 (轻量预测头 + 动态长度) | <1% | 是 (几小时) | 2-3× |
| Medusa (多并行头) | ~5% | 是 | 1.5-2.5× |
3.3.5 长上下文专用:Sliding Window、StreamingLLM、H2O
当 seq_len 进入 128K-1M 量级,即使 GQA+量化也撑不住。这一层的策略是「丢掉部分历史」(01 §4):
- Sliding Window(Mistral):只留最近 W 个 token,KV Cache 固定大小
- StreamingLLM:保留开头 attention sink + 最近窗口,兼顾稳定性和窗口
- H2O:保留 attention score 最高的 token,按重要性驱逐
- Scissorhands:用历史 attention pattern 预测未来不会被关注的 token
代价是丢失远距离信息,做长文档 QA 要谨慎。
3.4 L4 内存管理层:让显存物尽其用
3.4.1 PagedAttention:操作系统的虚拟内存搬到 GPU
vLLM 论文(SOSP 2023)的核心贡献。详见 01 §3。传统连续分配的三个问题:
- 内部碎片:预留 max_seq_len,浪费 60-80%
- 外部碎片:释放后不连续,新请求挤不进
- 过度预留:不知道生成多长,只能按最大值
PagedAttention 用 block table(页表)把逻辑 block 映射到任意物理 block,KV Cache 不需要连续。结果:
| 指标 | 传统 | PagedAttention |
|---|---|---|
| 内存利用率 | 20-40% | 96-98% |
| 并发请求数 | 1× | 2-4× |
| Copy-on-Write 共享 | 困难 | 天然支持 |
CoW 共享对 chat 场景(大量请求共享 system prompt)尤其有用。
3.4.2 RadixAttention:把前缀共享推到极致
SGLang 的核心创新(06 §3.3)。PagedAttention 的 CoW 是「请求间被动共享」,RadixAttention 是「主动用 Radix Tree 索引所有 KV 前缀」:
请求 A: "You are helpful. 用户问A" ┐
请求 B: "You are helpful. 用户问B" ├─ system prompt 前缀自动共享
请求 C: "You are helpful. 用户问C" ┘
多轮对话 / Agent / RAG 场景下,每一轮的 prefix 都在长,RadixAttention 的命中率远高于一次性 CoW。
3.4.3 KV Swap:OOM 时的逃生通道
当显存吃紧时(04 §6.2),vLLM 可以把低优先级请求的 KV Cache 换到 CPU 内存,等有空间再换回来。这等价于「GPU 上的 swap 分区」。
3.5 L5 调度层:从请求级到 iteration 级
3.5.1 静态 → 动态 → 连续批处理的演化
详见 批处理与调度。三代调度的核心差异:
静态批处理 (Static):
收 N 个 → 一起算 → 全部完成才能下一批
问题: 木桶效应、GPU 空转
GPU 利用率: 40-60%
动态批处理 (Dynamic):
时间窗口内凑批
问题: 还是要等最长的请求
GPU 利用率: ~60%
连续批处理 (Continuous / Iteration-level):
每一步 decode 都重算 batch:
完成的请求 → 移出
等待队列的新请求 → 立刻加入
GPU 利用率: 85-95%
吞吐: 比静态 2-4×
连续批处理 + PagedAttention 是「现代推理引擎的基石」(04 §4.4),互为前提:
- 没有 PagedAttention → 新请求加 batch 时分配不到连续 KV 空间
- 没有 Continuous Batching → PagedAttention 的细粒度内存管理用武之地不大
3.5.2 Chunked Prefill:解决 ITL 抖动
prefill 一次算 2048 token 可能要 100 ms,期间整个 batch 的 decode 全部停顿,用户感受是「流畅…卡顿…流畅」。Chunked Prefill(04 §5.2)把长 prefill 切成 512 一块,和 decode 交错调度:
传统: [████ prefill 2048 ████][decode][decode]...
↑ decode 全部停顿 100 ms
Chunked: [prefill 512][decode][prefill 512][decode][prefill 512][decode]...
↑ decode 每隔几 ms 就能跑一次,ITL 平稳
vLLM 的 --enable-chunked-prefill 就是这个。
3.5.3 Prefill-Decode 分离:下一代架构
两阶段硬件需求完全不同:
- Prefill 要算力(H100 > A100,FP8 Tensor Core)
- Decode 要带宽 + KV 容量(HBM3 > HBM2e)
混在一起部署的问题是硬件配比死板。P/D 分离(04 §5.3)把两类节点分开,KV Cache 用 GPUDirect RDMA 跨节点传输:
Prefill 节点 (高算力 H100 集群)
│ KV Cache via NVLink + IB + GDR
↓
Decode 节点 (高带宽集群)
代表系统:Mooncake、DistServe、Splitwise。挑战是 KV 传输开销和系统复杂度。
3.5.4 Preemption 与调度策略
04 §6 提到几种:
- FCFS:简单但长请求会阻塞
- SJF:优先短请求但长请求可能饿死
- 优先级队列:多租户/VIP 场景
- Preemption:显存紧张时把低优先级的 KV swap 到 CPU
3.6 L6 引擎层:集成 + 编译
引擎做的事是把 L1-L5 所有优化整合成一个可部署系统(详见 推理引擎架构)。三家主流的定位差异:
| 维度 | vLLM | TensorRT-LLM | SGLang |
|---|---|---|---|
| 核心创新 | PagedAttention | 深度硬件集成 + 编译 | RadixAttention |
| Runtime | Python + 自定义 op | C++ | Python |
| 硬件 | NVIDIA + AMD | 仅 NVIDIA | NVIDIA |
| 模型支持 | 最广 | 较窄(需编译) | 中等 |
| 学习曲线 | 平 | 陡 | 中 |
| 杀手场景 | 通用生产 | NVIDIA 极致性能 | 多轮对话/Agent |
| Benchmark (70B, A100×2) | TTFT 150ms / TP 2800 | TTFT 120ms / TP 3500 | TTFT 140ms / TP 3000 |
3.7 L1+L5 跨层:模型并行
模型放不进单卡时(70B FP16 = 140 GB)必须并行(06 §4):
- TP (Tensor Parallel):按权重列/行切,每层都要 AllReduce,需 NVLink,降单请求延迟,同节点内
- PP (Pipeline Parallel):按层切,层边界传激活,通信量小可跨节点,但有 pipeline bubble
- EP (Expert Parallel):MoE 专用,按专家切
典型部署:
Llama-3-70B 部署方案:
方案 A: 2×A100-80GB, TP=2 (NVLink 内)
方案 B: 4×A100-40GB, TP=4 (NVSwitch 内)
方案 C: 2×A100-80GB, TP=2 + INT4 (量化压到单卡也能塞下)
方案 D: 8×L40S, TP=2 + PP=4 (便宜卡 + 跨节点 PP)
4. 技术间的相互关系:协同与冲突
这是 synthesis 的关键章节——单独看每个技术都不难,难在它们组合时的化学反应。
4.1 协同关系矩阵
| A × B | 关系 | 说明 |
|---|---|---|
| PagedAttention × Continuous Batching | 强协同 | 互为前提,04 §4.4 |
| GQA/MLA × Continuous Batching | 强协同 | KV 越小 → batch 能更大 → GPU 利用率越高 |
| 量化 × KV Cache 量化 | 协同 | 一个压权重一个压 KV,加速可叠加 |
| FlashAttention × Chunked Prefill | 协同 | 每个 chunk 都用 FlashAttn,长上下文不爆显存 |
| RadixAttention × 多轮对话 | 强协同 | 多轮场景前缀命中率高,省 prefill |
| Speculative Decoding × FP8 量化 | 协同 | Spec 把 decode 转 compute-bound,FP8 Tensor Core 正好擅长 |
| TP × NVLink | 强协同 | 没 NVLink 的 TP 等于自残(GPU Comm) |
| P/D 分离 × GPUDirect RDMA | 强协同 | 没 GDR 的 P/D 分离 KV 传输成新瓶颈 |
| Prefix CoW × system prompt 多请求 | 强协同 | chat 场景节省巨大 |
4.2 冲突 / 边际递减
| 组合 | 关系 | 说明 |
|---|---|---|
| Speculative Decoding × 高并发 batching | 冲突 | batch 大时 GPU 已经 compute-bound,spec 收益骤降(05 §5.1) |
| INT4 量化 × 长上下文 attention 精度 | 边际损失 | 累积误差在长序列放大 |
| Sliding Window × 长文档 QA | 冲突 | 丢历史 = 丢答案 |
| TP=8 × 跨节点 | 冲突 | TP 每层 AllReduce,跨节点延迟爆炸(→ 改 PP) |
| Chunked Prefill × TTFT | 轻微冲突 | TTFT 略增(因为 prefill 被切片调度),但 ITL 改善 |
| Draft Model × 显存紧张 | 冲突 | 多加载一个小模型 |
| MLA × 已有 GQA 训练的模型 | 不兼容 | MLA 是架构改动,没法事后量化转换 |
4.3 一个典型组合的演化路径
把 Llama-3-70B 部署做到极致,一个典型的优化路径:
graph LR
A["朴素: FP16 + 静态 batch<br/>2×A100, 单卡可能 OOM"]
B["+ GQA<br/>(模型自带)"]
C["+ PagedAttention<br/>KV 利用率 30→97%"]
D["+ Continuous Batching<br/>GPU 利用率 40→90%"]
E["+ FlashAttention/Decode<br/>Attention 2-4×"]
F["+ FP8 量化<br/>显存减半, decode 2×"]
G["+ Chunked Prefill<br/>ITL 平滑"]
H["+ Speculative Decoding<br/>低并发场景再 2-3×"]
I["+ Prefix CoW / Radix<br/>chat 场景再省 30%"]
A --> B --> C --> D --> E --> F --> G --> H --> I
每一步对应的源页:
- B → 01 §2.5
- C → 01 §3
- D → 04 §4
- E → 06 §2.1-2.2
- F → 03 §3.4
- G → 04 §5.2
- H → 05
- I → 01 §3.4 + 06 §3.3
5. 主流推理引擎如何组合这些技术
5.1 技术支持矩阵
下面这张表是 §3 各项技术在三大引擎中的覆盖度(结合 06 §3 和各家公开文档):
| 技术 | vLLM | TensorRT-LLM | SGLang |
|---|---|---|---|
| PagedAttention | ✓ (原创) | ✓ | ✓ |
| Continuous Batching | ✓ | ✓ (Inflight) | ✓ |
| Chunked Prefill | ✓ | ✓ | ✓ |
| FlashAttention v2/v3 | ✓ | ✓ | ✓ (FlashInfer) |
| FlashDecode | ✓ | ✓ | ✓ |
| Kernel Fusion | 中等 | 极致 | 中等 |
| GPTQ / AWQ | ✓ | ✓ | ✓ |
| FP8 | ✓ | ✓ (H100 最优) | ✓ |
| KV Cache 量化 | ✓ (FP8/INT8) | ✓ | ✓ |
| Speculative Decoding | ✓ (Draft/EAGLE/Medusa) | ✓ | ✓ |
| Prefix CoW | ✓ | 部分 | RadixAttention |
| RadixAttention | × | × | ✓ (独家) |
| Tensor Parallel | ✓ | ✓ | ✓ |
| Pipeline Parallel | ✓ | ✓ | 部分 |
| Expert Parallel | ✓ | ✓ | ✓ |
| P/D 分离 | 实验性 | 部分 | 实验性 |
| LoRA 动态加载 | ✓ | 较弱 | ✓ |
| AMD GPU | ✓ (ROCm) | × | × |
| Constrained Decoding (JSON) | 较弱 | 较弱 | ✓ (DSL) |
5.2 引擎选型的核心权衡
- vLLM:生态最广、模型支持最全、社区最活、AMD 友好,但 Python overhead + 没有 RTRT-LLM 那种编译级 fusion
- TensorRT-LLM:C++ runtime + 深度 Kernel Fusion + FP8 Tensor Core 直接打通,单请求延迟最低;代价是要 build 模型 engine、学习曲线陡、模型支持窄
- SGLang:RadixAttention 在多轮/Agent/RAG 场景下吊打前两者,结构化输出 DSL 很顺手;通用吞吐接近 vLLM
5.3 同一份模型在三个引擎上的部署感受
vLLM:
pip install vllm
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-3-70B
→ 5 分钟跑起来
TensorRT-LLM:
pip install tensorrt_llm
python build.py --model llama --tp_size 2 --dtype float16 ...
trtllm-serve ...
→ build engine 半小时起步,但运行时极致
SGLang:
pip install sglang
python -m sglang.launch_server --model meta-llama/Llama-3-70B --tp 2
→ 5 分钟跑起来,DSL 写 agent 流程很爽
6. 选型决策树与场景化推荐
6.1 决策树
graph TD
Start[需要部署 LLM 推理] --> Q1{硬件是 NVIDIA?}
Q1 -- 否 --> AMD[vLLM + ROCm]
Q1 -- 是 --> Q2{场景类型?}
Q2 -- 本地/边缘 --> Local[llama.cpp + GGUF<br/>或 Ollama]
Q2 -- 服务端 --> Q3{核心诉求?}
Q3 -- 通用生产/快速迭代 --> vLLM[vLLM]
Q3 -- 极致延迟/吞吐 --> TRT[TensorRT-LLM]
Q3 -- 多轮对话/Agent/RAG --> SGL[SGLang]
Q3 -- 结构化输出 --> SGL
vLLM --> Q4{并发模式?}
TRT --> Q4
SGL --> Q4
Q4 -- 高并发吞吐 --> HC[关闭 spec decoding<br/>开 chunked prefill<br/>调大 max_num_seqs]
Q4 -- 低并发延迟 --> LC[开 spec decoding (EAGLE)<br/>开 FP8 量化<br/>用 TP 而非 PP]
6.2 场景 × 优化推荐
| 场景 | 关键优化栈 | 引擎首选 |
|---|---|---|
| ChatGPT 类公开服务(高并发) | GQA/MLA 模型 + PagedAttn + 连续批处理 + Chunked Prefill + FP8 + Prefix CoW | vLLM 或 TRT-LLM |
| 企业内部 Agent(多轮 + Tool) | RadixAttention + Constrained Decoding + KV 量化 | SGLang |
| 代码补全(强延迟敏感) | Speculative Decoding (EAGLE) + FP8 + TP=2 + NVLink | TRT-LLM |
| RAG 长上下文 (32K+) | FlashDecode + KV 量化 + Sliding Window / StreamingLLM (谨慎) | vLLM / SGLang |
| 私有化部署 + 单 4090 跑 70B | INT4 (AWQ) + CPU offload | llama.cpp / vLLM |
| 极端长上下文 (100K+) | MLA 模型 + FlashDecode + KV INT8 + RadixAttention | SGLang (DeepSeek-V2/V3) |
| 多租户 / 多 LoRA | LoRA 动态加载 + 优先级调度 | vLLM |
| 跨节点超大模型 (>200B) | TP (节点内) + PP (跨节点) + GDR + EP (MoE) | TRT-LLM / vLLM |
| 实时翻译/会议字幕 | Speculative Decoding + Streaming + chunked prefill | TRT-LLM |
| 边缘设备 (Mac / 树莓派) | GGUF Q4_K_M + llama.cpp | llama.cpp / Ollama |
6.3 性能调优 checklist
□ 模型架构层
□ 用 GQA/MLA 的模型,不用纯 MHA
□ 评估能否上 FP8(H100/H200 默认开)
□ 引擎配置层
□ 开启 PagedAttention(默认)
□ 开启 Continuous Batching(默认)
□ 视情况开 Chunked Prefill (`--enable-chunked-prefill`)
□ 调 `max_num_seqs` 到接近 OOM 的水位
□ 多轮场景开 prefix caching
□ 算法优化层
□ 权重量化:服务端首选 FP8 或 AWQ-INT4
□ KV 量化:长上下文场景开 FP8/INT8 KV
□ 低并发:开 Speculative Decoding (EAGLE-2 首选)
□ 长上下文:评估 sliding window / KV 驱逐
□ 硬件 / 并行层
□ 单节点优先 TP,确认 NVLink/NVSwitch 在线
□ 跨节点用 PP 而非 TP
□ P/D 分离场景确认 InfiniBand + GPUDirect RDMA
□ 监控层
□ 监控 TTFT / TPOT / ITL P99
□ 监控 KV Cache 利用率(应在 80-95%)
□ 监控 GPU 利用率(decode 阶段应在 85%+)
□ 监控 batch size 分布(不应贴着 max 跑)
7. 一张图:全栈优化总览
mindmap
root((LLM 推理优化全栈))
硬件 L1
HBM 带宽
SRAM 容量
Tensor Core FP8
NVLink/NVSwitch
GPUDirect RDMA
Kernel L2
FlashAttention
FlashDecode
Kernel Fusion
自定义 CUDA
算法 L3
MHA→GQA→MLA
权重量化
GPTQ
AWQ
FP8
GGUF
KV Cache 量化
Speculative Decoding
Draft Model
EAGLE-2
Medusa
长上下文策略
Sliding Window
StreamingLLM
H2O
内存管理 L4
PagedAttention
RadixAttention
Prefix CoW
KV Swap
调度 L5
Static / Dynamic
Continuous Batching
Chunked Prefill
P/D 分离
Preemption
优先级队列
并行 L1+L5
Tensor Parallel
Pipeline Parallel
Expert Parallel
引擎 L6
vLLM
TensorRT-LLM
SGLang
llama.cpp
服务 L7
OpenAI 兼容
多租户
LoRA 热加载
Constrained Decoding
8. 关键认知 Top 10
把 7 篇文章压成 10 条”必须刻在脑子里”的认知:
- Prefill compute-bound,Decode memory-bound —— 一切优化的分类基础(02)
- Decode 单请求延迟下限 = 模型大小 / HBM 带宽 —— 物理墙,量化和换硬件是唯二突破方法(02 §3.3)
- KV Cache 是 OOM 头号原因 —— 公式
2·L·kv_h·d·seq·bs·byte要会背(01 §2) - GQA → MLA 是模型架构层减 KV 的主线 —— 选模型先看 kv_heads(01 §2.4-2.6)
- PagedAttention + Continuous Batching 是现代推理引擎基石 —— 互为前提(01 §3, 04 §4)
- Batching 把 decode 推向 compute-bound —— GPU 利用率从 5% 提到 50%+(02 §5.3, 04 §1)
- 量化对 decode 加速近线性 —— prefill 增益有限,decode 直接翻倍(03 §4)
- Speculative Decoding 是无损加速 —— 数学上等价于 target 模型采样(05 §3)
- FlashAttention 把 attention 留在 SRAM —— 内存
O(seq²)→O(seq),长上下文的基础设施(06 §2.1) - NVLink/NVSwitch/GDR 决定并行架构的上限 —— TP 必须在 NVLink 内,P/D 分离必须有 GDR(GPU Comm)
9. 常见误区与反模式
把 7 篇文章里散落的「踩坑警告」集中起来,避免重复掉进去:
9.1 模型/架构层
- 「换了 H100 decode 就快了」 —— 错。decode 受 HBM 带宽限制,H100 比 A100 带宽提升 ~67%,速度提升大致同比例;想真正翻倍要靠量化或换模型架构(02 §3)
- 「GQA 一定比 MHA 差一点点」 —— 通常成立,但 MLA 反例:DeepSeek 报告 MLA 质量超过 MHA 同时 KV 减 93%(01 §2.6)
- 「INT4 量化精度损失不可接受」 —— 取决于方法。AWQ-INT4 + group_size=128 在 70B 模型上质量损失通常 <1%,且 decode 速度 4×(03 §3.2, §5)
- 「Sliding Window 是免费午餐」 —— 在长文档 QA 上可能掉关键信息(01 §4.1)
9.2 调度/批处理层
- 「batch 越大越好」 —— 错。batch 太大会导致 KV Cache OOM,且 prefill 阶段 batch 增益边际递减(04 §6, 02 §5.3)
- 「开了 chunked prefill 就稳了」 —— TTFT 会小幅变差(prefill 被切片),如果 SLA 卡 TTFT 要权衡(04 §5.2)
- 「Speculative Decoding 是万灵药」 —— 高并发 batch(>16)下 GPU 已经 compute-bound,spec 收益 → 0 甚至为负(05 §5.1)
- 「等到 OOM 再调 max_num_seqs」 —— 显存利用率应该恒定监控,不是出事才调(04 §6.2)
9.3 并行/部署层
- 「TP=8 比 TP=2 一定快」 —— 不一定。TP 每层 AllReduce,超过 NVLink 域(通常 8 卡)后通信成本爆炸(06 §4.1, GPU Comm)
- 「跨节点用 TP 没问题」 —— InfiniBand ~50 GB/s vs NVLink 900 GB/s,跨节点 TP 会掉性能 5-10×;跨节点用 PP(06 §4.2)
- 「P/D 分离一定更快」 —— KV 传输开销可能吃掉收益,没有 GDR + IB 的环境别上(04 §5.3, GPU Comm §3)
- 「LoRA 不影响吞吐」 —— 多 LoRA 动态加载需要 BatchedLoRA kernel 支持,否则会拖慢主路径
9.4 监控/Benchmark 层
- 「平均延迟好看就行」 —— 用户感知的是 P99,长尾被 prefill / preemption / spec miss 拉爆都会反映到 P99
- 「跑 vLLM 默认参数测 benchmark」 —— 不同引擎默认参数差异巨大,对比时要对齐
max_num_seqs、max_model_len、量化方式 - 「只看 throughput」 —— Throughput 高可能是把 batch 怼大换来的,TTFT/ITL 可能爆炸
10. 硬件对照速查表
把贯穿全文的几张 GPU 性能数据合到一张表(数据综合自 02 和 GPU Comm 各处):
| GPU | FP16 TFLOPS | FP8 TFLOPS | HBM 容量 | HBM 带宽 | NVLink | 适合阶段 |
|---|---|---|---|---|---|---|
| V100 | 125 | — | 32 GB | 0.9 TB/s | 300 GB/s (NVLink 2.0) | 已淘汰 |
| A100-40GB | 312 | — | 40 GB | 1.55 TB/s | 600 GB/s (NVLink 3.0) | 通用 |
| A100-80GB | 312 | — | 80 GB | 2.04 TB/s | 600 GB/s | 通用 |
| H100 SXM | 990 | 1979 | 80 GB | 3.35 TB/s | 900 GB/s (NVLink 4.0) | Prefill 王 |
| H200 | 990 | 1979 | 141 GB | 4.8 TB/s | 900 GB/s | Decode 王 |
| L40S | 366 | 733 | 48 GB | 0.864 TB/s | × (仅 PCIe) | 边缘 / 推理性价比 |
| B200 (Blackwell) | ~2500 | ~5000 | 192 GB | 8 TB/s | 1.8 TB/s (NVLink 5.0) | 下一代旗舰 |
性价比经验:
- H100 vs A100:prefill 提速 3×(990/312),decode 提速 ~1.6×(3.35/2.04),FP8 让 H100 在量化场景再翻一倍
- H200 vs H100:算力一样,但 HBM 多 76%、带宽多 43%,decode 和长上下文显著受益
- L40S:算力强但带宽弱,做 prefill 节点(04 §5.3 的 P/D 分离架构)很香,做 decode 不合适
11. 一个端到端案例:把 DeepSeek-V3 部署做对
把全栈优化整合到一个真实场景,作为压轴:
目标:部署 DeepSeek-V3 (671B 总参 / 37B 激活 / MoE),对外提供 OpenAI 兼容 API,要求 P99 TTFT < 1s,TPOT < 50ms,支持 32K 上下文。
全栈选择(按层):
L1 硬件:
- 8×H200 (NVLink 全连接 + 141GB HBM × 8 = 1.1 TB)
- 跨节点 InfiniBand 400G + GPUDirect RDMA
L1+L5 并行:
- TP=8 (节点内 NVLink)
- EP=8 (MoE expert 分到 8 卡)
- 大规模时 + PP 跨节点
L3 算法:
- MLA 架构 (KV/token/layer 仅 576 维, 1/57 of MHA)
- FP8 权重 (H100/H200 原生 Tensor Core)
- KV FP8 (长上下文额外省一半)
- EAGLE-2 投机解码 (针对低并发延迟场景)
L4 内存:
- PagedAttention (block_size=16)
- RadixAttention 风格 prefix cache (chat 高命中)
L5 调度:
- Continuous Batching
- Chunked Prefill (chunk=2048, 平滑 32K prompt 的 TTFT 影响)
- 预留 preemption 缓冲到 CPU swap
L6 引擎:
- SGLang (官方推荐, RadixAttention + MLA 支持完备)
- 或 vLLM (生态更广)
- TRT-LLM 也可, 但 MoE 编译路径复杂
预期表现(综合 05 §3.3、06 §5.2 benchmark 推算):
- TTFT (8K prompt): ~400-600 ms
- TPOT: ~25-35 ms (37B 激活 + FP8 + H200 带宽)
- Throughput: ~5000-8000 tokens/s @ 64 并发
- KV 利用率: 90%+ (PagedAttention)
- Prefix 命中: chat 场景 30-50% prefill 可省
会踩的坑:
- EP 通信开销:MoE 的 all-to-all 是新瓶颈,必须吃满 NVLink(GPU Comm §1)
- KV Cache 32K 长度下仍可能 GB 级 × 64 并发 → 必须配合 KV FP8 + max_num_seqs 上限
- Spec decoding 在高并发下要 disable,否则反而变慢
- 引擎对 MLA 的 kernel 支持还在演进,要锁版本
12. 参考与延伸
12.1 本文综合的 7 个源页面
- KV Cache:推理性能的命根子
- Compute-bound vs Memory-bound:推理的两大瓶颈
- 量化:INT8 / INT4 / FP8 到底在干嘛
- 批处理与调度:推理服务的灵魂
- 投机解码:突破 decode 一次只出一个 token 的限制
- 推理引擎架构:vLLM / TensorRT-LLM / SGLang
- GPU Communication:NVLink / NVSwitch / GPUDirect RDMA
12.2 进一步的横向阅读
- GPU Architecture Deep Dive —— SM、内存层次、Tensor Core 原理
- Megatron & Parallel —— TP/PP/DP/EP 原理
- LLM 推理优化摘要 —— 同主题的另一篇优化方法论
- AWP 六维 Breakdown —— 性能诊断框架,可定位优化打在哪
- Dynamic Batching 分析 —— 训练侧的动态凑批
12.3 关键论文 / 资料
- vLLM: Efficient Memory Management for LLMs with PagedAttention (SOSP 2023) — arXiv.06180
- GQA: Training Generalized Multi-Query Attention from Multi-Head Checkpoints — arXiv.13245
- MLA: DeepSeek-V2 — arXiv.04434
- EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty — arXiv.15077
- FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness (NeurIPS 2022)
这是一篇综合页(synthesis),不重复源页面里的公式推导和细节,而是把 7 篇文章的视角、抽象层次、相互关系拉到同一张地图上。如果只读这一页 → 拿到一份完整的「全栈优化心智模型」;如果带着具体问题来 → 跟着相对链接跳进源页拿细节。
知识库的其他 synthesis 页面(如 LLM 推理优化摘要)从「优化方法论」的角度切入,本页从「硬件→引擎」的层次结构切入,两者互补。
修改历史
修改历史1 次提交
- fix(wiki): clean all lint errors to enable strict CI (PR-3)xiaocheng··
75375ef