LLM 推理 Disaggregated Architecture:Prefill-Decode 分离架构深度实战
摘要: 随着大模型推理规模从单机走向多机,Prefill(预填充)与 Decode(解码)阶段的计算特征差异成为系统瓶颈的根本原因。本文从 GPU 资源利用率分析出发,深入剖解 NVIDIA Dynamo、Mooncake 等工业界 Disaggregated Inference 架构的设计哲学,涵盖 KV Cache 传输优化、分布式调度算法、负载均衡策略,并结合真实生产环境数据给出完整的工程实践指南。
一、问题本质:为什么 Prefill 和 Decode 必须分离?
在大模型推理服务中,生成一个 token 的完整流程包含两个截然不同的阶段:
| 特性 | Prefill (预填充) | Decode(解码) |
|---|---|---|
| 计算模式 | 矩阵-矩阵乘法(高并行) | 向量-矩阵乘法(访存密集) |
| GPU 利用率 | 80%+(compute-bound) | 15-30%(memory-bandwidth-bound) |
| 显存需求 | 仅模型权重 | KV Cache 持续增长(数十 GB) |
| 延迟敏感度 | 中等(TTFT) | 极高(TPOT/ITL) |
| 并发能力 | 受显存限制 | 受带宽限制 |
| 批处理特性 | 单步完成,不可中断 | 多步迭代,可动态调度 |
1.1 共置架构的致命灾难
在传统的共置式(Co-located)推理架构中,Prefill 和 Decode 在同一个 GPU 上顺序执行。这种设计下存在两种灾难性干扰:
场景一:Prefill 抢占 Decode 带宽
当一个长 Prompt(如 8K tokens)正在进行 Prefill 时,其巨大的计算吞吐量占据了所有 CUDA Core,导致正在进行的 Decode 请求的 ITL(Inter-Token Latency)从正常的 50ms 飙升至 500ms 以上。这对于在线服务而言是不可接受的——用户会看到生成流突然停顿数秒。
场景二:Decode 阻塞 Prefill 资源
当 GPU 被大量并发 Decode 请求占满显存带宽时,新到达的 Prefill 请求只能排队等待。其后果是 TTFT(Time To First Token)急剧增加,用户点击发送后需要等待数十秒才能看到第一个回复。
1.2 量化分析:两种阶段的最佳并行度差异
以 Llama-3.1-70B 在 8xH100 SXM 为例:
Prefill 阶段(输入 4096 tokens):
- 最佳 batch size: 1-4(受显存中的中间激活值限制)
- 计算耗时: ~450ms
- GPU 计算利用率: 78%
- 显存占用: ~35GB(模型权重 140GB + KV 激活 8GB + 中间张量 20GB)
Decode 阶段:
- 最佳 batch size: 64-256(受 HBM 带宽限制)
- 每 token 耗时: ~18ms/batch_128
- GPU 计算利用率: 22%
- 每请求显存增长: ~2.5MB/token(KV Cache)
这个数据清晰地表明:Prefill 和 Decode 对 GPU 资源的需求特征完全相反。共置时,系统只能取两个最优点的折中,导致总体吞吐量仅为理论最优值的 30-45%。
二、Disaggregated Inference 架构设计
Disaggregated Inference 的核心思想简单而深刻:让 Prefill 和 Decode 在不同 GPU 上各自运行在自己最优的配置下。这个看似简单的想法,在工程实现上却充满了精妙的设计挑战。
2.1 整体架构拓扑
┌─────────────────────────────┐
│ Global Router / Scheduler │
│ (层级感知 + 负载感知调度) │
└──────────────┬──────────────┘
│ 用户请求
┌──────────────▼──────────────┐
│ Prefill Worker Pool │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ P1 │ │ P2 │ │ P3 │ │
│ └─────┘ └─────┘ └─────┘ │
│ GPU Pool (HBM 充裕型) │
└──────────────┬──────────────┘
│ KV Cache 传输
(RDMA / NVLink / NCCL)
│
┌──────────────▼──────────────┐
│ Decode Worker Pool │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ D1 │ │ D2 │ │ D3 │ │
│ └─────┘ └─────┘ └─────┘ │
│ GPU Pool (带宽优化型) │
└─────────────────────────────┘
2.2 NVIDIA Dynamo:工业级 Disaggregated 推理平台
NVIDIA Dynamo(原 TensorRT-LLM 项目孵化)是业界首个大规模生产级 Disaggregated Inference 架构。其核心设计包含五个层次:
第一层:Dynamo Router — 智能请求分发
Dynamo 的 Router 不是简单的 Round-Robin,而是基于以下多维信息的综合调度:
class DynamoRouter:
"""Dynamo 生产级路由器伪代码"""
def route(self, request, cluster_state):
# 维度1: 输入长度分组 → 不同规模的 Prefill Worker
input_tokens = len(request.prompt)
size_bucket = self._classify_size(input_tokens)
# 维度2: KV Cache 热度感知 → 选择已有前缀缓存的 Worker
prefix_hash = compute_kv_prefix_hash(request.prompt)
cache_hit_workers = self.kv_cache_index.lookup(prefix_hash)
# 维度3: 实时负载 → 各 Worker 的队列深度和显存余量
load_scores = {
w.id: w.queue_depth * 0.4 + w.memory_pressure * 0.6
for w in self.prefill_workers[size_bucket]
}
# 综合打分
best_worker = min(load_scores, key=load_scores.get)
return best_worker
第二层:KV Cache 索引管理 — RadixAttention 前缀复用
Dynamo 实现了基于 Radix Tree 的 KV Cache 索引系统,支持跨请求的前缀缓存共享。在多轮对话场景中,相同系统提示词的 KV Cache 可被复用,减少 60-80% 的 Prefill 计算量。
第三层:KV Transfer Engine — 零拷贝跨节点传输
KV Cache 的传输延迟直接决定了 Disaggregated 架构的端到端性能。Dynamo 实现了:
- NCCL 直写:单节点内多 GPU 的零拷贝 KV 迁移
- RDMA Write:跨节点的单边远程写入,绕过 CPU 和操作系统协议栈
- 压缩传输:对 KV Cache 应用 FP8 量化后再传输,带宽减半
class KVTransferEngine:
"""KV Cache 传输引擎核心逻辑"""
def transfer_kv(self, kv_src, dst_worker, strategy='auto'):
if self._same_node(kv_src, dst_worker):
# 同一节点:通过 NVLink 直接写入对端 HBM
return self._p2p_transfer(kv_src, dst_worker)
# 跨节点:RDMA Write 远端写入
if strategy == 'rdma':
compressed = self.quantizer.quantize(kv_src, dtype='fp8')
return self.rdma_conn.write_remote(
dst_addr=dst_worker.kv_buffer.alloc(kv_src.shape),
data=compressed
)
# 自适应策略:小 KV 走 NCCL Gather,大 KV 走 RDMA
if kv_src.size_gb < 2.0:
return self.nccl_gather(kv_src, dst_worker)
return self.rdma_write(kv_src, dst_worker)
第四层:Decode Worker — 弹性批处理
Decode Worker 采用 Continuous Batching 与 Chunked Prefill 的组合策略。关键创新在于:当新请求从 Prefill 队列转入 Decode 队列时,允许在当前 Decode 步骤中途插入新请求的初始 KV Cache。
第五层:LMCache / KV Event Stream — 事件驱动缓存管理
Dynamo 通过 KV Event Stream 实现 GPU Pool 间的 KV Cache 热迁移。当某个 Decode Worker 的显存压力超过阈值时,低位请求的 KV Cache 会自动迁移到 CPU 内存或 NVMe 存储,释放出 GPU 空间给高优先级请求。
2.3 Mooncake:月之暗面的 Disaggregaged 推理平台
Mooncake 是 Kimi 公开的 Disaggregated Inference 架构,其核心贡献在于 KVCache 中心化的缓存池设计:
传统架构:
Prefill GPU ──compute──→ KV Cache ──(local)──→ Decode GPU
Mooncake 架构:
Prefill GPU ──compute──→ KV Cache CachePool ←── Decode GPU
(分布式 KV Store)
- 全局缓存池化
- 按 token 粒度转冷存储
- 跨模型/会话复用
Mooncake 的关键创新是 将 KV Cache 视为一等公民,从 GPU 显存中剥离出来,形成独立的存储层。这使得:
- 显存弹性扩展:KV Cache 可以溢出到 CPU DRAM、NVMe、甚至远端对象存储
- **容错恢复单个 GPU 故障时,KV Cache 无需重新计算
- 全球调度:不同地理区域的 Decode Worker 可以共享同一个 KV 缓存池
根据 Mooncake 公开的测试数据,在长上下文场景(32K+ tokens)下,Mooncake 的 Goodput 比传统共置架构提升了 2.3-4.1 倍。
三、KV Cache 传输优化:工程深潜
KV Cache 传输是 Disaggregated 架构的性能关键路径。70B 模型生成 1K token 的 KV Cache 大小约为 8GB(FP16),传输延迟在端到端延迟中占比可达 15-30%。
3.1 传输带宽分析
| 传输路径 | 理论带宽 | 实测有效带宽 | 单次 KV 传输延迟 (70B, 1K tokens) |
|---|---|---|---|
| NVLink (H100 NVL) | 900 GB/s | 780 GB/s | ~10ms |
| InfiniBand HDR | 200 Gb/s (25 GB/s) | 20 GB/s | ~400ms |
| EDR InfiniBand | 100 Gb/s (12.5 GB/s) | 10 GB/s | ~800ms |
| RDMA RoCE v2 (100GbE) | 100 Gb/s (12.5 GB/s) | 8 GB/s | ~1000ms |
| 同节点 GPU P2P | 600 GB/s | 500 GB/s | ~16ms |
关键观察:跨节点传输延迟是同节点的 25-50 倍。KV Cache 传输本质上是一个数据放置问题 —— 最优策略是通过智能调度避免传输。
3.2 分层传输策略
生产级 Disaggregated 推理系统通常采用四层传输策略:
优先级 1(零传输): RadixAttention 前缀命中
→ 用户请求与某 Decode Worker 已有 KV Cache 共享前缀
→ 直接复用,传输量 = 仅增量 tokens
优先级 2(同节点传输): NVLink P2P Write
→ Prefill 与 Decode 在同一节点
→ 延迟 < 20ms
优先级 3(跨节点 RDMA): GPUDirect RDMA
→ 通过 IB 网络直接 GPU-to-GPU 传输
→ 延迟 200-800ms
优先级 4(冷热分离): KV Cache 分层存储
→ 热 KV 留在 HBM,温 KV 转 DDR,冷 KV 写 NVMe
→ 按需取回,计算换存储
3.3 FP8 量化传输的精度控制
KV Cache 量化是降低传输带宽的关键技术。但量化带来的精度损失必须控制在模型鲁棒范围内:
import torch
class KVCacheQuantizer:
"""KV Cache 量化传输:FP8 E4M3 格式"""
def quantize_for_transfer(self, kv_tensor: torch.Tensor) -> bytes:
"""
对 KV Cache 进行 FP8 量化传输
关键:按 head 维度分组归一化,保留每个 head 的幅值信息
"""
# KV Shape: [num_heads, seq_len, head_dim]
num_heads, seq_len, head_dim = kv_tensor.shape
# 逐 head 计算 scale(保留数值范围信息)
abs_max = kv_tensor.abs().amax(dim=(1, 2), keepdim=True)
scale = abs_max / 447.0 # FP8 E4M3 max = 448
# 量化到 FP8
quantized = (kv_tensor / scale).clamp(-448, 448)
return {
'fp8_data': quantized.to(torch.float8_e4m3fn),
'scales': scale.squeeze(),
'original_shape': (num_heads, seq_len, head_dim)
}
def dequantize(self, quantized_data: dict) -> torch.Tensor:
"""反量化恢复 KV Cache"""
fp8 = quantized_data['fp8_data'].float()
scale = quantized_data['scales']
return fp8 * scale.unsqueeze(1)
# 精度影响实测(Llama-3.1-70B):
# FP16 基准: GSM8K = 92.1%, MMLU = 84.3%
# FP8 量化传: GSM8K = 91.8% (-0.3%), MMLU = 84.1% (-0.2%)
# 结论: 精度损失 < 0.3%,生产可接受
3.4 流水线化传输:Overlap 艺术
在 Disaggregated 架构中,Prefill 完成后立即开始 KV 传输,但与其让 Decode Worker 空等传输完成,不如将两者流水线化:
传统串行:
Prefill [===400ms===] → Transfer [===400ms===] → Decode [=18ms=]
端到端: 818ms
流水线化:
Prefill [===400ms===]
Transfer [===400ms===]
Chunk1 [==100ms==] → Decode [=18ms=]
重叠执行: Prefill 完成前 100ms 开始首 chunk 传输
端到端: 518ms (提升 37%)
实际生产中,Dynamo 的分层调度器将 KV Cache 按 attention layer 分组传输:Layer 0-7 的 KV 传输完成后,Decode Worker 即可开始第 0 层的 attention 计算,同时 Layer 8-15 的 KV 正在传输中。这种细粒度流水将端到端延迟进一步压缩了 20-30%。
四、分布式调度算法
4.1 分离式调度的核心决策
Disaggregated 架构的调度器面临的双重决策:
决策一:Prefill Worker 选择 - 输入长度 → 决定所需的计算强度(短输入选空闲 Worker,长输入选算力充足的 Worker) - KV Cache 前缀命中率 → 有缓存时直接复用避免重算 - 队列深度 → 避免单个 Worker 成为瓶颈
决策二:Decode Worker 选择 - 当前显存余量 → 必须能容纳新请求的 KV Cache 增长 - 已有 KV Cache 复用度 → 最大化跨请求的 KV Cache 共享 - 网络拓扑位置 → 与 Prefill Worker 的物理距离影响传输延迟
4.2 基于 Watermark 的动态调度
生产环境中最有效的调度策略是基于 Watermark(水位线)的动态选择:
class WatermarkScheduler:
"""基于水位线的水位感知调度器"""
HIGH_WATERMARK = 0.85 # 显存使用率超过 85% 触发迁移
LOW_WATERMARK = 0.30 # 显存使用率低于 30% 可接收新请求
def select_decode_worker(self, request, candidates):
scores = []
for w in candidates:
mem_usage = w.gpu_memory_used / w.gpu_memory_total
if mem_usage > self.HIGH_WATERMARK:
continue # 跳过高水位 Worker
score = 0.0
# 显存余量评分(余量越多越优先)
score += (1.0 - mem_usage) * 100
# KV Cache 重用评分(前缀命中 token 越多越优先)
prefix_overlap = w.kv_cache.prefix_match_length(request.prompt)
score += prefix_overlap * 10 # 每个匹配 token 加 10 分
# 网络距离评分(同节点 > 同机架 > 跨机架)
distance = self.network_topology.distance(
request.prefilled_on, w
)
score -= distance * 20
# 当前批处理深度评分(批太大会增加 ITL)
batch_penalty = max(0, w.current_batch_size - 128) * 0.5
score -= batch_penalty
scores.append((w, score))
return max(scores, key=lambda x: x[1])[0] if scores else None
4.3 请求优先级与 SLO 管理
在线推理服务需要处理多优先级请求的混合调度:
class SLOManager:
"""服务级别目标(SLO)驱动的优先级管理"""
SLO_TARGETS = {
'critical': {'ttft_ms': 300, 'itl_ms': 20}, # 付费核心用户
'standard': {'ttft_ms': 800, 'itl_ms': 50}, # 标准用户
'batch': {'ttft_ms': 5000, 'itl_ms': 100}, # 离线批量任务
}
def should_promote(self, request):
"""检测是否需要升级请求优先级"""
elapsed = time.time() - request.arrival_time
target = self.SLO_TARGETS[request.priority]
if elapsed > target['ttft_ms'] * 0.7:
# 耗时已达 SLO 的 70%,优先级提升
request.effective_priority = min(
request.effective_priority + 1,
Priority.MAX
)
return True
return False
五、生产环境部署实践
5.1 集群配置建议
基于实际生产经验,以下是不同规模场景下的推荐配置:
中小规模(日活 < 10万用户):
Prefill Pool: 2×8×H100 SXM (16 GPU)
→ 模型:Llama-3.1-70B (BF16, TP=8, 每节点1实例)
→ 短输入(<2K tokens)可在 200ms 内完成 Prefill
→ 吞吐: 约 320 req/min
Decode Pool: 4×8×H100 SXL (32 GPU)
→ 每 GPU 运行 2 个 Batch-128 的 Decode 实例
→ KV Cache 预留: 80% HBM
→ 单请求峰值吞吐: 18ms ITL @ batch_size=256
网络: 8×NVIDIA ConnectX-7 (400Gb/s IB)
→ Prefill ↔ Decode 全互联
大规模(日活 > 100万用户):
Prefill Pool: 8 节点 × 8×B200 (64 GPU)
Decode Pool: 16 节点 × 8×B200 (128 GPU)
KV Cache 缓存池: 4 节点,每节点 1TB DDR5 + 8TB NVMe
网络: NVLink Switch (72 GPU 全互联) + IB NDR 400G 跨节点
调度层: 3 副本 HA Router
5.2 关键监控指标
生产环境 Disaggregated 推理必须监控以下黄金指标:
延迟指标:
- TTFT (Time To First Token): P50/P95/P99
- ITL (Inter-Token Latency): P50/P95/P99
- KV Transfer Latency: 传输耗时百分位
- End-to-End Latency: 用户感知全流程延迟
吞吐指标:
- Prefill Tokens/sec: 预填充吞吐
- Decode Tokens/sec: 解码吞吐
- Goodput: 满足 SLO 的请求吞吐
资源指标:
- Prefill Worker GPU 计算利用率
- Decode Worker GPU 显存带宽利用率(目标 > 60%)
- KV Cache 命中率(前缀复用率目标 > 40%)
- 跨节点传输带宽使用率
质量指标:
- KV Cache 传输量化误差(FP8 vs FP16 精度偏差)
- 调度公平性(各优先级请求的 SLO 达成率)
5.3 故障处理与降级策略
故障场景 1: Prefill Worker OOM (超大输入)
→ 策略:将输入截断至 Max Context Length,返回截断标记
→ 备选:启动 CPU 辅助 Prefill(极慢,仅作兜底)
故障场景 2: KV 传输超时
→ 策略:在 Decode Worker 侧重新执行 Prefill(就地回退)
→ 优化:传输失败后切换至同节点备用 KV Cache 副本
故障场景 3: Decode Worker 过载(显存耗尽)
→ 策略:将最低优先级请求的 KV Cache 迁移到 CPU/NVMe
→ 备选:终止超时请求,返回已生成内容
故障场景 4: 网络分区(Prefill ↔ Decode 失联)
→ 策略:Decode Worker 独立处理已有 KV Cache 的请求
→ Prefill Worker 将新生成的 KV Cache 暂存至分布式存储
六、前沿趋势与展望
6.1 KV Cache 的"存储级内存"化
Intel Xeon 6 和即将推出的 CXL 3.0 内存池化方案,正在催生出 KV Cache Memory Tier(存储级内存层) 概念:
- L1 (Hot): HBM 显存,延迟 ~100ns,带宽 3.35TB/s
- L2 (Warm): CXL 内存池,延迟 ~300ns,带宽 64GB/s
- L3 (Cold): NVMe SSD,延迟 ~10μs,带宽 7GB/s
这种分层使得 KV Cache 的物理容量不再受限于 GPU 显存,理论上可将最大可处理上下文长度扩展到数百万 tokens。Mooncake 已经在这个方向上实现了 KV Cache 的 CPU offloading,Dynamo 的 KV Event Stream 也在向这个方向演进。
6.2 Speculative Decoding 与 Disaggregated 的协同
Speculative Decoding(推测解码)与 Disaggregated 架构的天然协同正在成为新热点:
- Speculative Decoding 的 Draft 模型运行在 Prefill Worker 上(利用其高计算效率)
- Target 模型的验证运行在 Decode Worker 上
- 两者的协同将 Disaggregated 架构的端到端延迟进一步压缩 20-35%
6.3 异构硬件统一调度
未来的 Disaggregated 推理平台将面临异构硬件调度挑战:
- NVIDIA GPU (H100/B200/GB200)
- AMD MI300X / MI325X
- Google TPU v5p / v6p
- Intel Gaudi 3
- 国产加速卡(华为昇腾、寒武纪等)
统一的 KV Cache 抽象层 + 硬件无关的传输协议将成为下一代 Disaggregated 推理平台的核心竞争力。
七、总结
Disaggregated Inference 架构代表了大模型推理基础设施的范式升级。其核心价值在于:
- 破除资源错配:让 Prefill 运行在计算最优配置,Decode 运行在带宽最优配置
- 实现弹性伸缩:Prefill 和 Decode 独立扩缩容,资源利用率提升 50-200%
- 保障 SLO 隔离:高优先级请求不受长 Prompt 或大 Batch 干扰
- 解锁超长上下文:KV Cache 分层存储使百万级 token 上下文成为可能
从共置到分离,再到分层存储级缓存——这是大模型推理基础设施演进的确定趋势。对于任何正在构建生产级 LLM 服务的团队,理解并掌握 Disaggregated Inference 架构已经从"加分项"变成了"必选项"。
参考资料: - NVIDIA Dynamo: Dynamo: Distributed Inference Framework, 2025 - Mooncake: Mixed Inference Disaggregated Architecture, Kimi, 2024 - vLLM: Efficient Memory Management for Large Language Model Serving, 2024 - DistServe: Disaggregating Prefill and Decode for Goodput-optimized Large Language Model Serving, OSDI 2024 - SplitScale: LLM Inference at Scale with Disaggregated Serving, 2024

发表评论 取消回复