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 显存中剥离出来,形成独立的存储层。这使得:

  1. 显存弹性扩展:KV Cache 可以溢出到 CPU DRAM、NVMe、甚至远端对象存储
  2. **容错恢复单个 GPU 故障时,KV Cache 无需重新计算
  3. 全球调度:不同地理区域的 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 架构代表了大模型推理基础设施的范式升级。其核心价值在于:

  1. 破除资源错配:让 Prefill 运行在计算最优配置,Decode 运行在带宽最优配置
  2. 实现弹性伸缩:Prefill 和 Decode 独立扩缩容,资源利用率提升 50-200%
  3. 保障 SLO 隔离:高优先级请求不受长 Prompt 或大 Batch 干扰
  4. 解锁超长上下文: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

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部