Skip to content
Published on

PD 分离并不会提升吞吐量 — 预填充/解码分离实际买到的是什么

分享
Authors

引言 — 同居在一块 GPU 上、性格截然不同的两份工作

LLM 推理分成两个阶段,这已经是常识了。把整段 prompt 一次性推过一次前向传播来构建 KV 缓存的预填充(prefill),以及一个个吐出 token 的解码(decode)。每次聊到KV 缓存时都会提到的,正是这两个阶段。

重要的是,这两者的性格恰好相反。照搬 SGLang 文档的说法,预填充是处理整个输入序列的计算密集型(computation-intensive)工作,而解码是管理 KV 缓存的内存密集型(memory-intensive)工作。预填充在燃烧 GPU 的计算单元,解码则因为每个 token 都要重新读一遍模型权重和整个 KV 缓存,被内存带宽死死拴住。

把两份性格不同的工作放到同一块 GPU 上、用同一个调度器来跑,会发生什么?拆开之后真的会变好吗?本文要讲的正是这场「拆分」——预填充/解码分离(PD disaggregation)——在 2026 年究竟走到了哪一步,以及为什么互联网上流传的倍数不能照单全收。

放在同一块 GPU 上为什么会出问题 — 干扰

SGLang 文档把统一引擎里出现的问题钉死为两类。

其一,预填充中断(Prefill Interruption)。 照搬文档原句,是「到来的预填充批次会频繁打断正在进行的解码批次,给 token 生成带来显著延迟」。画张图就清楚了:某个用户正在一个个接收 token、进行流式输出,这时旁边来了一条 8000 token 的 prompt。那次预填充会把整块 GPU 占用一阵子,正在流式输出的用户的下一个 token 也就相应地推迟了。对用户而言,那是文字正流畅地滚动着,突然戛然而止的一瞬间。

其二,DP 注意力失衡(DP Attention Imbalance)。 在数据并行注意力中,如果一个 DP worker 同时处理预填充批次、另一个处理解码批次,解码延迟就会增加。

TensorRT-LLM 的技术博客给出了同样的诊断——在统一服务中会出现「上下文处理拖慢 token 生成」的干扰,交互性因此下降。这篇博客用一句话概括了问题的本质:「优化 TTFT 这样的一个指标,往往是以牺牲 TPOT 这样的另一个指标为代价的。」

这就是核心所在。在同一块 GPU 上,预填充和解码是争夺同一份资源的两个相互冲突的目标。把 batch 调大,吞吐量会上升,但尾部延迟会崩掉;把预填充切碎(chunked prefill),干扰是少了,但预填充效率会下降。想用一个调度器同时满足两个目标,这件事本身在结构上就是一种妥协。

于是就分离 — PD 分离的结构

想法很简单:既然性格不同,那就分别配给不同的硬件。

按照 vLLM 文档的定义,分离式预填充是把预填充和解码阶段放到不同的 vLLM 实例上运行,再通过连接器在两者之间搬运 KV 缓存。实际部署大致长这样。

                     [ 代理 / 路由器 ]
                        |          |
              请求 ---->|          |
                        v          v
              [ 预填充实例 ]        [ 解码实例 ]
               GPU 0-3               GPU 4-7
               Prompt -> KV          KV -> Token 流
                        |          ^
                        |  KV 缓存  |
                        +--- RDMA --+
                          (连接器)

需要三个部件。

  1. 预填充实例 — 接收 prompt,构建 KV 缓存。
  2. 解码实例 — 接收那份 KV 缓存,吐出 token。
  3. 连接器与代理 — 搬运 KV 缓存,并协调请求该发往哪一侧。

这样一来,就可以给每个阶段分别套用并行化策略了。预填充用低 TP、解码用高 TP——或者反过来。vLLM 文档把这一点列为该功能的第一项好处:「分别调优 TTFT 和 ITL」。第二项是「控制尾部 ITL」。因为预填充作业再也无法打断解码,解码 GPU 上吐出的 token 就有了稳定的节奏。

在 vLLM 中,这个功能目前仍标记为 experimental。照搬文档原句:「此功能为实验性功能,可能会发生变化。」

该怎么读这些数字 — 是 goodput,不是吞吐量

这里是本文的核心。

搜索 PD 分离,「2 倍」「7 倍」这样的数字会扑面而来。可偏偏 vLLM 官方文档里钉着这样一句大写字母:

"Disaggregated prefill DOES NOT improve throughput."(分离式预填充不会提升吞吐量。)

看起来像是矛盾。但两者其实都对。弄清楚原因之后,看待 PD 分离的眼光会彻底改变。

细想一下就很显然。PD 分离并不会凭空变出更多 GPU。 把 8 块 GPU 分成 4 块跑预填充、4 块跑解码,总计算量不可能因此增加。相反,把 KV 缓存挪到网络上是一份新增的工作,若按纯粹的总工作量来算,反而会增加。TensorRT-LLM 的博客也承认了这一点——「分离会带来传输 KV 缓存块的开销」。

那么,那些倍数究竟测的是什么?答案是 goodput

这个概念的出处是 PD 分离的鼻祖论文 DistServe(Zhong 等,OSDI 2024)。标题本身就是「Goodput-optimized」。goodput 大致这样定义——在同时满足 TTFT 与 TPOT 约束的前提下,系统能承受的最大请求速率。如果说单纯的吞吐量是「每秒吐出了多少个」,那 goodput 就是「每秒以承诺的质量吐出了多少个」。

这个差异有多大,进入 vLLM 的 MORI-IO 连接器博客说得很清楚。那篇博客对 goodput 的定义是这样的:

"Goodput = maximum request rate (req/s) such that requests satisfy both TTFT < T_ttft and ITL < T_itl."

也就是说,没能满足 SLO 的请求不算数。在吞吐量的计算里,一个耗时 3 秒的 TTFT 也算一次;但在 goodput 的计算里,它算零次——因为用户大概率早就把标签页关掉了。

归纳起来是这样:

  • 吞吐量(纯粹的 tokens/s,忽略延迟):PD 分离不会提升它。反而会因为传输开销略有损失。——这正是 vLLM 文档所说的那件事。
  • goodput(满足 SLO 的处理量):PD 分离会大幅提升它。——这正是厂商博客们所测量的那件事。

同一个系统,不同的尺子。这就是为什么看到互联网上的倍数时,首先要确认用的是哪把尺子

把那些倍数拆开来看

用这副眼镜重新读一遍公开的数字。以下全部是厂商/作者自测,并附上各自的测量条件——条件才是数字的意义所在。

DistServe(Zhong 等,OSDI 2024,作者自测)。 论文的标题级数字是「请求数多 7.4 倍」或「SLO 紧 12.6 倍」。但紧接着就跟了一个条件——「在超过 90% 的请求都保持在延迟约束内的前提下」。这不是吞吐量的倍数,而是在固定住 SLO 达成率的前提下的请求速率倍数。而且论文自己也说,这个倍数会随模型、应用、延迟要求而变化。

TensorRT-LLM(NVIDIA 自测,GB200)。 这里的数字尤其有教育意义。在 DeepSeek R1 上,输入 4400 / 输出 1200 的条件下,不开 MTP 是 1.4~1.8 倍,开 MTP 是 1.6~2.5 倍。输入 8192 / 输出 256 时,4-GPU 最高 1.73 倍,8-GPU 是 2 倍。而最关键的一条——输入 4096 / 输出 1024 时,「在每用户每秒 50 token 这一点上改善 1.7 倍」。请把最后这句话再读一遍:这是在每用户每秒 50 token 这一延迟目标被固定住的前提下的吞吐量倍数。一旦松开延迟约束,这个倍数就站不住。Qwen 3 在输入 8192 / 输出 1024 的条件下,报告出 1.7~6.11 倍这样宽的区间——区间这么宽本身,就是「条件决定一切」的证据。

而且 NVIDIA 还老实地加了一条脚注:理论上的「rate-matched」分析,和实际端到端基准测试之间,存在 0~25% 的差距,原因是「理想化的假设」以及「KV 缓存传输开销」。等于是厂商亲口说了,别把理论倍数当真。

llm-d on AWS(AWS 自测,2026 年 3 月 16 日)。 GPT-OSS 模型,ml.p6-b200.48xlarge 实例,4 个预填充 pod(TP1)加 1 个解码 pod(TP4),输入输出各 1024 token,并发最高 128。结果是「随着并发提升,相对标准 vLLM 部署,每秒 token 数最多提升 70%」。这里同样带着「随着并发提升」这个条件——意味着负载低时没有收益。AWS 的作者们还补了一句:「但这并不适合所有工作负载。请在更大的模型、更长的输入序列、稀疏 MoE 架构上尝试。」

看出规律了吗?每一个数字都固定住了延迟目标或负载条件。这不是巧合,而是因为那正是 PD 分离在出售的东西。

搬运 KV 的管道 — 真正的工程在这里

PD 分离的想法,一段话就能讲完。难的是管道。预填充 GPU 生成的 KV 缓存必须搬到解码 GPU 上,这件事并不小,而且这次传输会原封不动地叠加到 TTFT 上。

所以 2026 年真正的竞争,发生在传输层

NIXL(NVIDIA Inference Xfer Library)是目前用得最广的一条主线。照搬代码仓库的说明,它「旨在加速 NVIDIA Dynamo 等 AI 推理框架中的点对点通信,并通过模块化插件架构,为多样化的内存(CPU、GPU)和存储(文件、块、对象存储)提供统一抽象」。它是 Apache 2.0 协议,后端插件包括 UCX、POSIX、OBJ、AZURE_BLOB、HF3FS、MOONCAKE、GUSLI、UCCL、GDS、GPUNETIO、LIBFABRIC 等。简而言之,这是一层抽象,让 KV 缓存既能走 InfiniBand,也能走 NVMe,还能走 S3。

Mooncake 是 SGLang 的默认传输引擎,SGLang 支持 Mooncake、NIXL、ASCEND 三种后端。走 Mooncake 路径时,需要用 --disaggregation-ib-device 指定 InfiniBand 设备。

vLLM 这边目前的连接器列表是这样——NixlConnectorLMCacheConnectorV1MooncakeConnectorMoRIIOConnector(仅限 ROCm)、MultiConnectorOffloadingConnectorFlexKVConnectorV1,以及用作示例的 ExampleConnector。内部抽象分三块——Connector(生产者与消费者之间的 KV 检索)、LookupBuffer(insert 非阻塞,drop_select 阻塞)、Pipe(单向 FIFO)。

这里不能漏掉的一点是,管道又会反过来变成硬性要求。RDMA 网络实际上是前提条件。 这就是为什么 AWS 在讲运行 llm-d 时,会把 EFA 和 libfabric 插件放在一起谈;也是为什么 SGLang 要求指定 InfiniBand 设备的原因。要是把这套设计架在普通以太网上,省下来的 ITL 又会以传输延迟的形式吐回去。

2026 年 4 月,MORI-IO — 一个具体的测量

把抽象的话题落到一个具体的测量上。2026 年 4 月 7 日,vLLM 博客上线了一篇关于 MORI-IO 连接器的文章,由 AMD 和 Embedded LLM 团队撰写,测量在 2026 年 3 月 12 日进行。先说明一点——这是 AMD 自测

MORI-IO 是搭建在 MORI(Modular RDMA Interface)框架之上、基于 RDMA 的 KV 缓存连接器,已贡献进 vLLM。可以把它理解成在 AMD GPU(ROCm)阵营里,填补了 NIXL 那个位置的东西。

测量条件如下。

  • 硬件:8 块 AMD Instinct MI300X(每块 192GB),2 路 AMD EPYC 9654 96 核
  • 软件:Ubuntu 22.04 LTS,ROCm 7.0.51831,vLLM 0.16.0rc1.dev1
  • 模型:Qwen/Qwen3-235B-A22B-FP8
  • 工作负载:输入 2000 token,输出 1000 token,共 100 个请求,请求速率 0.5~10 req/s
  • SLO:TTFT 低于 1 秒,ITL 低于每 token 50ms
  • 配置:预填充在 GPU 0-3,解码在 GPU 4-7,外加一台代理服务器

以下是请求速率 8 req/s 这一点上报告的结果。

配置满足 SLO 的请求相对 goodput
标准 (1× TP8)26/1000.9 倍
标准 (2× TP4)30/1001 倍(基准)
MORI-IO Read (1P+1D)70/1002.4 倍
MORI-IO Write (1P+1D)73/1002.5 倍

这张表里最重要的不是倍数,而是为什么会失败。照搬博客原句:

「两种分离模式都彻底消除了 ITL 违规。剩下的失败,是随着请求速率上升而出现的 TTFT 超限。」

这一句话总结了 PD 分离的真面目。ITL 违规归零了。 解码 GPU 上再也没有预填充能插进来,这是理所当然的。但失败并没有消失,而是转移到了 TTFT 那一边。瓶颈不是被消除了,而是被搬走了,只不过这笔交易恰好划算而已。

Read 模式和 Write 模式的差异,也是同一个故事的延续。

  • Read 模式:解码方通过 RDMA 从预填充方把 KV 拉过来。按博客的说法,「TTFT 会增加至少一次完整预填充前向传播(代理序列化)加上 RDMA 传输时间」。
  • Write 模式:预填充方在计算过程中就把 KV 推给解码方。「TTFT 只增加 RDMA 传输时间,由于这次传输与预填充计算是重叠的,净惩罚更小。」

所以 Write 是 73,Read 是 70。按博客的说法,是因为「并发的代理调度降低了 TTFT」。也就是说,这 3 分之差的真面目,最终是 TTFT 惩罚的大小。

还有一条脚注悄悄挂在那里:「按 MORI-IO 连接器的要求,禁用了前缀缓存。」 两种分离配置都是如此。这不是一条无关紧要的脚注——下一节会讲到。

不是免费的 — 老实交代成本

现在来看账单。

TTFT 会变差。 正如前面看到的那样。KV 缓存跨越网络所需的时间会叠加到 TTFT 上,Read 模式下还要再加上代理序列化。请记住,在 MORI-IO 的测量中,没能满足 SLO 的 27~30 个请求,全部都是 TTFT 超限。PD 分离是一笔把 ITL 问题换成 TTFT 问题的交易。如果你的瓶颈就是 TTFT,这笔交易是亏本的。

可能与前缀缓存冲突。 在 MORI-IO 的测量中,前缀缓存是作为连接器的硬性要求被关掉的。这为什么伤人——因为前缀缓存,能在长系统 prompt 或多轮对话中把预填充成本整个抹掉,是大多数实务工作负载中单项最大的优化。如果你的流量是共享长公共前缀的聊天机器人流量,那么关掉前缀缓存换来的 2.5 倍 goodput,是否真的优于开着前缀缓存的统一服务,完全不是不言自明的。这一项必须用你自己的流量亲自测一遍。(连接器和版本不同,情况也会不同,请核实你打算使用的组合当前的限制。)

需要 RDMA 网络。 InfiniBand 或 RoCE,如果在 AWS 上则是 EFA。这是硬件采购和网络设计的问题,不是打开一个开关就能解决的事。

需要多块 GPU。 最低配置是预填充 1 块 + 解码 1 块,实战配置只会更大——MORI-IO 的测量把 8 块 GPU 按 4:4 分,AWS 的案例是 4 个预填充 pod 配 1 个解码 pod。对于只用两三块 GPU 跑的服务而言,这不是一个值得讨论的话题。

运维复杂度会增加。 一个实例会变成两种实例 + 代理/路由器 + 传输层。需要根据工作负载调优预填充与解码的比例(这正是 AWS 那篇文章指出的那一项),故障模式也会随之增多。连性能剖析都会变得麻烦——SGLang 文档写明,需要对预填充 worker 和解码 worker 分别做性能剖析。

受模型架构限制。 SGLang 的暂存缓冲区优化是给非 MLA 模型(GQA、MHA)用的,文档明确写着「MLA 模型(如 DeepSeek-V2/V3)不应该开启这个标志」。TensorRT-LLM 表示,这种方法对「长输入序列、中等长度输出」的工作负载最有利。如果是短 prompt 配长输出,预填充本来就不是瓶颈,拆分的理由也就不足。

仍处于 experimental 阶段。 至少在 vLLM 里是这样。

那么,你该不该用它

判断标准出乎意料地清晰。MORI-IO 的博客直接给出了答案。

「如果生产负载下 ITL p99 超过了 SLO:请分离——这是主要的使用场景。」

「低请求速率、短 prompt:标准服务就够了。」

把到目前为止的素材叠加上去,可以这样归纳。

用了值回票价的情况

  • 尾部 ITL 是 SLO 违规的真正原因。有流式输出卡顿的抱怨,测一下 p99 ITL,发现罪魁祸首是预填充干扰。
  • 长输入 + 中等长度输出的工作负载。(TensorRT-LLM 明确指出的条件)
  • 负载确实很高。请记住,AWS 测量中的收益是随着「并发提升」才出现的。
  • 已经具备 RDMA 网络和富余的 GPU。
  • 大模型,尤其是稀疏 MoE。(AWS 建议的条件)

属于过度或亏本的情况

  • 瓶颈是 TTFT。分离会让 TTFT 变得更差
  • 前缀缓存是你的主力优化——尤其是共享长公共系统 prompt 的聊天机器人。
  • 负载低,或者 prompt 很短。
  • GPU 没几块,或者没有 RDMA。
  • 只是单纯觉得吞吐量不够用。——这种情况下,分离不是答案。正如 vLLM 文档用大写字母说的那样。

最后一项是最常见的误解。如果你是抱着「想降低 GPU 成本」这个动机来考察 PD 分离的,那方向就错了。那是量化或 batch 调优要解决的问题。PD 分离出售的是可预测性,不是容量。

结语

归纳起来是这样。预填充是计算密集型,解码是内存密集型,把两者放在同一块 GPU 上,预填充就会掐断解码。PD 分离把两者拆到不同的 GPU 上,从源头上消除了这种干扰,并让每个阶段的并行化可以分别调优。MORI-IO 测量中 ITL 违规彻底消失,就是证据。

代价是,必须把 KV 缓存搬到网络上,那份时间会叠加到 TTFT 上,还需要 RDMA 网络、多块 GPU、更高的运维复杂度,并且可能与前缀缓存这类既有优化相冲突。而纯粹的吞吐量——照搬 vLLM 文档的说法——并不会增加。

所以 PD 分离不是「更快的服务」,而是「守约的服务」。它不是用同样的 GPU 吐出更多东西的技术,而是让吐出来的东西都落在 SLO 之内的技术。一旦模糊了这个区分,就会被互联网上的倍数骗到——因为那些数字全都是在固定住延迟目标的前提下测出来的 goodput。

所以顺序应该是这样:先测你的 p99 ITL。如果它超过了 SLO,而且元凶是预填充干扰,那时候再把分离拿出来。没测就先上分离,等于是用一副非常昂贵的药,去治一种根本不存在的病。

参考资料