跳转至

PD 分离与推理架构设计

更新日期:2026-04-15


一、为什么要 PD 分离

flowchart LR
    user["请求"]
    pre["Prefill<br/>计算密集<br/>(读 prompt)"]
    kv["KV Cache<br/>传输"]
    dec["Decode<br/>带宽密集<br/>(逐 token 生成)"]
    out["Output"]

    user --> pre --> kv --> dec --> out

    classDef stage fill:#fff,stroke:#cc785c,color:#1a1a1a;
    class user,pre,kv,dec,out stage
阶段 瓶颈资源 适合硬件
Prefill 算力(FLOPs) H100 / B200(高 TFLOPS)
Decode 显存带宽(HBM) H200 / B200(更大 HBM)

混合部署时同 GPU 同时做两件冲突的事 → 互相挤压

  • Prefill 占满 SM 时,Decode 卡顿(latency 高)
  • Decode 占满 HBM 带宽时,Prefill 慢(throughput 低)
  • batch 越大冲突越严重

PD 分离让两类请求各跑各的 GPU,整体吞吐提升 2-4×(DistServe paper 实测)。

1.1 根本原因

混合部署时,同一 GPU 要同时做两件本质冲突的任务。分离后,每类 GPU 做自己最擅长的事。参考 DistServe (Zhong et al., OSDI 2024)


二、PD 分离核心技术

2.1 KV Cache 传输

class PDDisaggregator:
    def __init__(self):
        self.prefill_workers = [PrefillWorker(gpu=i) for i in range(n_prefill)]
        self.decode_workers = [DecodeWorker(gpu=i) for i in range(n_decode)]
        self.router = Router()

    async def serve_request(self, request):
        # 1. Router 分配
        prefill_worker = self.router.assign_prefill(request)
        decode_worker = self.router.assign_decode(request)

        # 2. Prefill
        kv_cache = await prefill_worker.prefill(request.prompt)

        # 3. KV Cache 传输 (关键!)
        # 选项 A: 通过 NCCL (GPU 直接传)
        # 选项 B: 通过 CPU + IB (慢)
        # 选项 C: 异步流水线 (边计算 layer_i+1 边传 layer_i)
        await transfer_kv_cache(prefill_worker, decode_worker, kv_cache)

        # 4. Decode
        async for token in decode_worker.decode(request, kv_cache):
            yield token

2.2 流水线传输优化

# 朴素做法: prefill 完成 → 全量传输 → 开始 decode
# 问题: 传输时 GPU 空闲,首 token 延迟高

# 优化: 逐层流水线
def pipelined_transfer(prefill_gpu, decode_gpu, n_layers):
    for layer_i in range(n_layers):
        # Prefill 计算 layer_i
        kv_i = prefill_gpu.compute_layer(layer_i)

        # 异步传输 layer_i 的 KV (不阻塞下一层计算)
        async_send(kv_i, decode_gpu)

        # 同时启动 layer_i+1 的计算
        # 最后一层完成时, 前面的 KV 已经传输完毕

    # 等最后一层传输完成
    await wait_all_transfers()

三、架构设计

3.1 比例配置

工作负载 Prefill : Decode 比例 备注
闲聊(短 prompt 短回答) 1:3 - 1:5 Decode 主导
代码 / 长文本生成 1:2 Decode 略多
RAG(长 prompt 短回答) 1:1 Prefill 偏重
代码 review(很长 prompt) 2:1 Prefill 主导
Reasoning model(长 thinking) 1:5+ Decode 极重

实操:先 1:1 起步监控两侧排队,按队列深度动态扩缩容。

3.2 同步 vs 异步 PD

flowchart LR
    subgraph sync["同步 PD"]
        s1["请求<br/>Prefill"] --> s2["等 KV<br/>传完"] --> s3["Decode<br/>开始"]
    end

    subgraph async["异步 PD"]
        a1["请求<br/>Prefill 开始"] --> a2["分层<br/>边算边传"]
        a2 --> a3["Decode<br/>(部分 KV 到达即可启动)"]
    end

    classDef stage fill:#fff,stroke:#cc785c,color:#1a1a1a;
    class s1,s2,s3,a1,a2,a3 stage
维度 同步 PD 异步 PD
实现复杂度 中-高
TTFT 高(等 KV 全到) (部分 KV 到即可启动)
吞吐
故障恢复 简单(重试) 复杂(中间状态)
SGLang 默认
vLLM 默认 实验性

工业级 deploy 都用异步 PD(SGLang 路线)。同步只在调试 / 简单原型用。


四、SGLang 的 PD 分离实现

SGLang 在 2025 年原生支持 PD 分离,是目前开源方案中最成熟的。参考 SGLang Disaggregation

4.1 架构

# SGLang 启动 PD 分离集群
# Prefill workers:
python -m sglang.launch_server \
    --model-path deepseek-v3 \
    --disaggregation-mode prefill \
    --tp 4 \
    --host 0.0.0.0 --port 30000

# Decode workers:
python -m sglang.launch_server \
    --model-path deepseek-v3 \
    --disaggregation-mode decode \
    --tp 4 \
    --host 0.0.0.0 --port 30001 \
    --prefill-urls http://prefill_worker_1:30000,http://prefill_worker_2:30000

# Client 直接连 decode worker, 由它协调 prefill

4.2 性能数据

公开 benchmark(SGLang + DeepSeek-V3 + AMD MI300X):

配置 TTFT TPOT Throughput
混合部署(baseline) 850ms 35ms/tok
PD 分离同步 720ms 28ms/tok 1.6×
PD 分离异步 510ms 22ms/tok 2.4×

异步 PD 在 TTFT + 吞吐两个维度都显著优于混合部署。

4.3 DeepSeek-V3 PD 实际数据

在 96×H100 集群上,SGLang PD 分离达到:52,300 input tok/s + 22,300 output tok/s per node。参考 SGLang DeepSeek Blog


五、vLLM 的 PD 分离(llm-d)

vLLM 通过 llm-d 项目提供 PD 分离支持,但成熟度不如 SGLang。

# vLLM 的实验性支持
vllm_args = {
    '--kv-transfer-config': '{"kv_connector": "PyNcclConnector"}',
    '--disaggregated-serving': True,
}

# 数据: vLLM + llm-d 0.3 on H200
# 32-way EP: ~2.2K tok/s/GPU  
# 96-way EP: ~2.0K tok/s/GPU


六、PD 分离的工程挑战

挑战 描述 为什么这是难题 缓解方案 实践建议
KV Cache 传输带宽 大上下文的 KV Cache 可达数 GB(如 128K context + 70B 模型,KV Cache 约 20-40GB) KV 传输延迟直接加到 TTFT 上;若传输耗时 >100ms,PD 分离的 TTFT 优势被抵消 用 NVLink(900GB/s)或 InfiniBand(400Gb/s)而非 TCP(~10GB/s);逐层流水线传输(边算边传) 同机架内走 NVLink/NVSwitch 最优;跨机架至少用 IB HDR/NDR;KV Cache 可用 FP8 量化减半传输量
Prefill/Decode 负载不均 不同时段的请求模式变化(白天 RAG 密集 prefill 多,晚上闲聊 decode 多) 静态比例配置无法适应流量波动,导致一侧 GPU 空闲另一侧排队 动态调整 pool 大小:监控 prefill/decode 队列长度,按比例弹性伸缩 建议设置自动伸缩策略:队列深度 >阈值时扩容,空闲 >5 分钟时缩容;保留 10-20% buffer 应对突发
故障恢复 Prefill worker 挂掉时,已分配给它的请求和正在传输的 KV Cache 都丢失 单体部署只需重试请求即可;PD 分离中请求状态跨两个 worker,需要协调恢复,否则用户看到中断 Checkpoint + 重试:decode worker 检测 prefill 超时后自动将请求重新分配到健康的 prefill worker 设置 prefill 超时阈值(如 10s);实现 prefill 幂等性(重复 prefill 不影响正确性);多副本 prefill pool 提升容错
延迟敏感的短请求 Prompt <100 token 的短请求,PD 分离的 KV 传输开销可能超过 prefill 本身耗时 短 prompt prefill 仅需 1-5ms,但 KV 传输至少 1-10ms(取决于网络),PD 分离反而增加延迟 路由策略区分长短请求:短请求走混合模式(同 GPU 上 prefill+decode),长请求走 PD 分离 设置 prompt 长度阈值(建议 512 token);低于阈值的请求直接在 decode worker 上做 prefill,跳过传输
多模型共享集群 不同模型(如 7B 和 70B)的 KV Cache 维度、层数、精度不同,无法混用 PD 分离的 KV 传输协议需要知道 KV 格式(head_dim, n_layers, dtype);混用会导致数据错位 每个模型维护独立的 prefill/decode pool;或设计统一 KV 序列化协议(header 描述格式) 多模型场景建议用 Kubernetes 做 pool 隔离,每个 Deployment 对应一个模型的 PD 集群

七、何时 PD 分离真正值得

flowchart TB
    start["要部署 LLM"]
    q1{"QPS"}
    q2{"prompt 长度"}

    start --> q1

    q1 -->|"<100"| simple["混合部署<br/>简单维护"]
    q1 -->|"100-1000"| q2
    q1 -->|">1000"| pd["强制 PD 分离<br/>+ 异构硬件"]

    q2 -->|"短 (<512 tok)"| simple2["混合部署<br/>PD 收益有限"]
    q2 -->|"长 (>512 tok)"| pd2["PD 分离<br/>SGLang 异步"]

    classDef stage fill:#fff,stroke:#cc785c,color:#1a1a1a;
    classDef decision fill:#f5f3eb,stroke:#bdb9ab,color:#1a1a1a;
    class start,simple,simple2,pd,pd2 stage
    class q1,q2 decision

生产建议: - 小流量 (<100 QPS):不用 PD 分离,简单部署 - 中流量 + 短 prompt:可选,收益有限 - 大流量 + 长 prompt (RAG/代码):强烈推荐 PD 分离


八、未来方向

方向 描述 为什么值得探索 当前进展与挑战 实践建议
多级 PD Prefill → Chunked Decode → Final Decode,将 decode 进一步拆分为"前几十 token 快速生成"和"后续批量生成" 前几个 token 对用户体验最关键(TTFT),后续 token 可以批量优化吞吐;多级拆分允许不同优先级调度 调度复杂度显著增加;目前 SGLang/vLLM 尚无原生支持,需自行实现中间层 先观望;当单级 PD 的 TTFT 无法满足 SLA 时再考虑多级拆分
跨机房 PD Prefill 在算力密集机房(如 H100 集群),Decode 在内存优化机房(如 H200/CPU 集群) 不同机房可以采购不同硬件配置,整体 TCO 降低 20-40%;算力/内存需求的异构性天然适合异地部署 跨机房网络延迟(通常 1-10ms)会直接加到 KV 传输时间;需要高带宽专线(至少 100Gbps)和可靠的故障转移 仅在自有数据中心且两个机房有专线互联时考虑;公有云上跨 region 延迟太高不划算
异构 PD Prefill 用高算力 GPU(H100/H200),Decode 用高性价比 GPU(L40S/A100)甚至专用推理芯片 Decode 几乎不用算力,用旗舰 GPU 做 decode 是浪费;L40S 价格约为 H100 的 ⅓ 但 HBM 带宽够用 不同 GPU 的驱动/CUDA 版本需要兼容;KV Cache 的精度和格式需要在异构 GPU 间保持一致 高性价比路线:Prefill 用 H100 SXM5 + Decode 用 L40S 48GB,整体成本降低约 30%
Cache 持久化 KV Cache 从 GPU 卸载到 CPU DRAM 或 NVMe SSD,复用历史会话(如多轮对话中前几轮的 KV) 多轮对话中每轮都重新 prefill 历史 context 极其浪费(相同前缀反复计算);持久化 KV 后只需 prefill 增量部分 CPU/SSD 读取带宽(约 10-50GB/s)远低于 HBM(约 2-5TB/s),KV 加载延迟可能达数十 ms;需要 LRU 淘汰策略管理缓存容量 对多轮对话和 RAG(相同文档库的 KV 可复用)ROI 最高;建议 CPU DRAM 做热缓存 + SSD 做冷缓存的两级架构

参考文献


上级 · G. 推理与部署