更新于

PD 分离到底该配多少 P 和 D?


做 PD 分离时,最容易问错的问题是:P:D 有没有一个标准答案?

没有。1:3、1:1、3:1 都可能合理。比例不是先定下来的架构参数,而是模型、硬件、流量和 SLO 算出来的容量结果。

网上常有人把 SGLang 的 96 张 H100 实验解读成固定的 P:D 配比。其实原文分别用 4 个节点测 Prefill、9 个节点测 Decode,而且明确说两边是独立压测,假设另一阶段资源无限。那组数据说明两侧各自能跑多快,不是一个线上集群的固定比例。

真正要算的只有两本账:

业务每秒给 P、D 分别制造多少工作?
一张卡或一个完整实例,能在 SLO 内处理多少工作?

用前者除以后者,卡数就出来了。

P 和 D 不是同一种负载

Prefill 一次处理整段输入,矩阵乘规模大,通常更吃计算;Decode 每一步只生成少量 Token,却要持续读取权重和历史 KV,并长期保存请求状态,通常更受显存容量、带宽和通信影响。

阶段主要工作最先关注核心指标
Prefill处理输入 Token,生成首份 KV计算吞吐、通信TTFT、input token/s
Decode持续生成 Token,持有并扩展 KVKV 容量、带宽、通信TPOT/ITL、并发、output token/s

所以输入越长,P 的工作通常越重;输出越长,请求在 D 里停留越久,D 的压力越大。长文档短回答偏 P,长推理、长生成偏 D,并不矛盾。

还有一个容易漏掉的点:长输入不只影响 P。Prefill 结束后,整段输入对应的 KV 会进入 D,因此它也会吃掉 D 的初始 KV 容量。

先定实例形状,再算实例数量

1. 权重能不能装下

权重显存先按下面的式子估:

Mweight参数量×权重精度字节数M_{\mathrm{weight}} \approx \text{参数量} \times \text{权重精度字节数}

300B FP8 权重大约是 300GB。两张 141GB H200 合计 282GB,连纯权重都放不下,更不用说运行时缓冲区和 KV Cache,因此实例至少要从 4 卡起步。

MoE 要分清两件事:权重存储看总参数量,单 Token 计算量主要看激活参数量。专家没有被当前 Token 选中,不代表它可以不放进显存。

2. 一个请求要占多少 KV

普通 MHA/GQA 模型可以先这样估:

Ktoken=2×Nlayer×Nkv head×Dhead×SkvK_{\mathrm{token}} = 2 \times N_{\mathrm{layer}} \times N_{\mathrm{kv\ head}} \times D_{\mathrm{head}} \times S_{\mathrm{kv}} Kreq=Ktoken×Lctx,Lctx=Lin+LgeneratedK_{\mathrm{req}} = K_{\mathrm{token}} \times L_{\mathrm{ctx}}, \qquad L_{\mathrm{ctx}} = L_{\mathrm{in}} + L_{\mathrm{generated}}

这里的 2 是 K 和 V,SkvS_{\mathrm{kv}} 是每个 KV 元素的字节数。

DeepSeek-R1/V3 使用 MLA,必须按压缩潜变量和推理框架的实际缓存布局计算,不能直接套 MHA/GQA 公式。

3. D 先过显存,再过 TPOT

实例中可用于 KV 的显存是:

MKV=MtotalMweightMruntimeMreserveM_{\mathrm{KV}} = M_{\mathrm{total}} - M_{\mathrm{weight}} - M_{\mathrm{runtime}} - M_{\mathrm{reserve}}

显存能容纳的并发上限为:

Bmemory=MKVKreqB_{\mathrm{memory}} = \left\lfloor \frac{M_{\mathrm{KV}}}{K_{\mathrm{req}}} \right\rfloor

但放得下不等于跑得动。并发增加以后,每个 Decode Step 要读取更多权重和 KV,还要承担 TP/EP 通信。最终并发要取显存上限和 SLO 上限的较小值:

BD=min ⁣(Bmemory,BSLO)\boxed{B_D = \min\!\left(B_{\mathrm{memory}}, B_{\mathrm{SLO}}\right)}

BSLOB_{\mathrm{SLO}} 不适合只靠纸面带宽反推。它受 Batch、上下文、Kernel、量化、并行方式和通信影响,应该直接从目标 TPOT/ITL 下的 Profiling 结果里取。

4. P 看目标 TTFT 下的有效吞吐

稠密模型的 Linear 计算量可以粗略按每 Token 2P2P 估算:

FLOPstoken2P\mathrm{FLOPs}_{\mathrm{token}} \approx 2P

因此单卡 Prefill 产能可先估为:

CP单卡峰值算力×MFU2PC_P \approx \frac{\text{单卡峰值算力} \times \mathrm{MFU}}{2P}

MoE 的 PP 主要看激活参数,还要补上 Attention、Router、All-to-All 和其他运行时开销。

这个公式只适合给初始量级。真正用于规划的 CPC_P,应该是目标 ISL、Batch 和 TTFT 下实测出来的 Goodput。TP 也不是越大越好:加卡可能缩短单请求 Prefill 时间,但通信开销会上升,单位卡吞吐未必更高。

配比公式其实很简单

设请求到达率为 λ\lambda,平均有效输入长度为 Lin,effL_{\mathrm{in,eff}},平均输出长度为 LoutL_{\mathrm{out}};P、D 每卡在 SLO 内的实测产能分别为 CPC_PCDC_D

那么两侧卡数是:

NP=λLin,effCP,ND=λLoutCDN_P = \frac{\lambda L_{\mathrm{in,eff}}}{C_P}, \qquad N_D = \frac{\lambda L_{\mathrm{out}}}{C_D}

两式相除:

NPND=CDCP×Lin,effLout\boxed{ \frac{N_P}{N_D} = \frac{C_D}{C_P} \times \frac{L_{\mathrm{in,eff}}}{L_{\mathrm{out}}} }

这就是 P:D 的来源:一半由模型、硬件、并行和 Kernel 决定,另一半由业务的输入输出比例决定。

λ\lambda 在比例里约掉了,但它仍然决定绝对卡数。Prefix Cache 命中后,P 真正需要计算的输入 Token 会减少,所以这里用的是 Lin,effL_{\mathrm{in,eff}};D 侧仍要按实际驻留的完整上下文核算 KV。

为了只看输入输出比例,先暂时固定 CPC_PCDC_D。假设某组 Profiling 得到:

P:1300 input token/s/GPU
D:3750 output token/s/GPU

那么:

P:D2.88×Lin,effLout\mathrm{P:D} \approx 2.88 \times \frac{L_{\mathrm{in,eff}}}{L_{\mathrm{out}}}
流量输入:输出理论 P:D
等长对话1K:1K2.88:1
长文档短回答8K:1K23:1
长推理、长生成1K:8K1:2.8

这组数字只演示公式,不是推荐配置。真实环境中输入变长也会增加 D 的 KV 水位,CDC_D 不会始终保持 3750;模型、Batch 和 TPOT 目标变化时,两侧产能同样要重新测。

用 Little’s Law 再校验一次 D

吞吐账算完后,还要看 D 池会积累多少请求。

请求在 D 中的平均停留时间近似为:

TDLout×TpotT_D \approx L_{\mathrm{out}} \times T_{\mathrm{pot}}

根据 Little’s Law:

QD=λTDλLoutTpot\boxed{Q_D = \lambda T_D \approx \lambda L_{\mathrm{out}} T_{\mathrm{pot}}}

每秒 10 个请求、平均输出 1000 Token、TPOT 20ms,D 池平均会有约 200 个活跃请求。输出增至 8000 Token,其他条件不变,并发会增至约 1600。

这个结果应该和“D 实例数 × 单实例有效并发”大致对得上。差得太多,通常是输出长度分布、TPOT、排队时间或单实例并发估错了。

KV 容量要看 P95/P99 上下文,平均吞吐则要看时间加权后的真实分布。长请求占比不高却特别吃显存时,单独分池通常比全局按 P99 预留更划算。

生产上按这个顺序落地

  1. 画像流量:统计峰值请求率、ISL、OSL、上下文分布、Prefix Cache 命中率和 TTFT/TPOT SLO。
  2. 确定 D 实例形状:先装下权重,再算 KV 容量,最后压测目标 TPOT 下的有效并发。
  3. 确定 D 数量:用输出 Token Goodput 算一次,再用 Little’s Law 从并发侧校验。
  4. 确定 P 形状和数量:根据 TTFT 选并行组,用实测 Prefill Goodput 计算实例数。
  5. 按完整实例取整:P 是 TP=8、D 是 TP=4 时,都不能部署半个实例。
  6. 加余量后压测:考虑故障、突发流量、Kernel 波动和长尾请求,最终看满足 SLO 的 Goodput,而不是裸吞吐。

纸面计算负责给出第一版配置,最终比例必须由目标流量回放决定。

Decode 有状态,还能不能扩缩容

可以,但不是无成本迁移。

D 池可以增加完整的 Decode 副本,让新请求进入新副本。缩容时,先把目标副本摘流,再等待存量请求结束;如果系统支持请求迁移,也通常是把 Prompt 加已生成 Token 重新提交,在新 Worker 上重建 KV,而不是把运行中请求的 GPU KV、CUDA 状态原封不动搬过去。

所以准确的边界是:

D 池可以做副本级弹性

运行中请求的 GPU KV 可以无缝实时迁移

面试时怎么讲

我不会先拍一个 1:1 或 1:3。先用权重显存确定 P、D 的实例形状,再分别测两侧在目标 SLO 下的单位产能。P 卡数等于每秒输入 Token 量除以 P 每卡 Goodput,D 卡数等于每秒输出 Token 量除以 D 每卡 Goodput,所以 P:D 等于 D/P 每卡产能比乘有效输入/输出长度比。

D 还要额外过两道约束:显存能容纳多少 KV,以及这些并发下 TPOT 能否达标,最终取两者的最小值。然后用 Little’s Law 校验整个 D 池的并发:到达率乘平均输出长度再乘 TPOT。

因此长输入短输出通常偏 P,长推理、长生成通常偏 D。最后还要考虑 MLA、MoE、Prefix Cache、完整并行组取整和故障余量,用真实流量压测,不能照抄别人的比例。


封面摄影:mos design,拍摄于日本东京池袋。图片来源:Unsplash,按 Unsplash License 使用。