Files
tech/知识/知乎专栏/Zoe Lee/2026-08-05_推理_PD分离的绝佳入门教程_DistServe.md
T
arno c0ba3fb853 文档(金鹏): 2026-08-06 章节 48 篇文章摘要归档
- 46 篇原文+摘要双文件归档(按 来源/作者 分层,复用本地归档 20 篇+新抓取 26 篇)
- 即梦生成 9 组主题配图(大图+列表缩略图)存入 知识/金鹏/20260806/
- 章节重组为 9 个主题分组并挂接摘要引用
2026-08-06 18:00:50 +08:00

123 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 【推理】PD分离的绝佳入门教程 —— DistServe
> **来源**:知乎专栏
> **作者**Zoe Lee
> **发布日期**2026-08-05
> **原文链接**https://zhuanlan.zhihu.com/p/19666783423
---
作为推理服务中PD分离的技术的经典方法之一,DistServe(OSDI 2024)无疑为广大学者提供了一份绝佳的入门教程。该工作详细分析了PD分离的技术动机、提出了通俗易懂的PD分离算法思想、并充分开源了代码,让每一个想了解PD分离技术的人都能够"亲自把玩"。
本文为在精度论文并部署代码进行多组实验后整理的"玩后感",会从PD分离技术动机、DistServe项目算法思想、code实现以及个人理解等方面展开介绍。本人初学,望看到本文的大佬们多多指点交流~
## 1. PD分离技术动机
我们知道一条请求在推理的过程中需要经过两个步骤:第一步,根据输入序列的内容生成第一个token,该过程称为Prefill;第二步,根据输入序列以及之前已经生成的token生成下一个token,该过程称为Decoding。随着"以存代算"的KV-Cache技术的引入,大多推理过程避免了在Attention结构的重复计算,这导致Prefill与Decoding在执行时存在着较大的差异。
为什么Prefill和Decoding存在较大的差异?
首先我们从计算过程上去直观理解两个步骤的区别。在Prefill阶段,模型输入prompt的所有token,经过一步计算后得到第一个输出,与此同时每个token在计算时产生的KV-Cache被储存下来,而在Decoding阶段,每个新token的计算都会涉及到KV-Cache的读取与存储,而计算量相比Prefill而言被大大降低了,取而代之的是高频的存取操作带来的压力,这便是KV-Cache技术带来的Prefill和Decoding的差异化。
这种差异是否会导致放在一个batch中处理会相互拖后腿?
论文通过实验给出了肯定的答案。下图表示在全部是decoding状态的batch中加入一个做prefill的请求导致的延迟变化。蓝色线条的起点表示只处理一条prefill的延迟,蓝色后面的点与起点的差值都可以看做添加decoding状态的请求对该prefill状态的请求带来的延迟危害,而蓝色与橙色对应节点的差值可以看作添加的一个prefill状态的请求对decoding状态的请求batch带来的延迟危害。
![图1:混合batch中的延迟干扰](https://pica.zhimg.com/v2-4cc03f245d34af4919b94ed441ed7ab2_1440w.jpg)
截取自论文
综合分析,两阶段混合推理带来的主要问题如下:
1. 调度低效:在相同GPU上进行不同状态的调度会造成decoding等待prefill的现象,并且GPU在进行decoding会导致资源低利用率;
2. 资源和并行策略的耦合:两阶段的差异对于资源和并行策略的需求不同,相同GPU上部署不可避免的会导致两阶段资源和并行策略的共享。
至此,PD分离就成为了一种最为直接的解决思想。
## 2. P/D阶段特性分析
在正式提出算法前,论文对于P和D阶段的batch策略和并行方案进行了分析。对于batch策略,论文通过以下实验对比了两阶段的不同特点:
![图2P/D阶段batch策略对比](https://pic2.zhimg.com/v2-146793643fe85191ddcddcd819bb8a11_1440w.jpg)
截取自论文
Prefill阶段并不是batch size越大吞吐越大,吞吐随batch size的变化取决于输入文本的长度,因此在设置batch size时要考虑输入长度。而增加batch size对于Decoding阶段是一个避免低吞吐的好方法。
对于并行方式,为了分析Prefill阶段对于并行策略的偏好,论文首先利用M/D/1排队模型对请求队列进行了建模,进而TTFT就可以用请求在系统内的平均等待时间表示,加入Pipeline并行和Tensor并行的影响后,TTFT建模结果分别如下:
```
PP=2: D + (R*D^2) / (4*(2 - R*D))
TP=2: D/K + (R*D^2) / (2*K*(K - R*D))
```
其中D为请求的执行时间,R为到达率,K为TP带来的影响系数,由于通信代价,通常 1<K<2 。当到达率R很小时,第一项执行时间为主要作用,这时TP的效果会更好,当R增加时第二项其主要作用,PP的效果则更好,结合实验结果看更清楚:
![图3Prefill阶段并行模式分析](https://pica.zhimg.com/v2-d99d7374b8e5312e86090f8ee214b376_1440w.jpg)
截取自论文
这一实验结论对根据不同场景下设置并行模式起到了参考作用。而Decoding阶段的并行模式分析同理,TP可以降低延迟,但是过大的TP会引入过量通信,延迟降低的优势也就不再明显,PP虽不影响单个请求的执行时间,但可以加大吞吐。
![图4Decoding阶段并行模式分析](https://pic1.zhimg.com/v2-9af2a96c68bb5d49781757849d701992_1440w.jpg)
截取自论文
不过对于这一部分的分析,本人也做了粗略的实验比较了一下两个阶段TP与PP的影响,发现对于给定P/D两阶段的卡数的情况下似乎并行策略的影响不大~但是论文这部分的分析确实具有一定的启发性。
接下来正式介绍DistServe项目的算法思想。整个项目分成两大部分:设计并行模式、执行分离式推理。
### 3.1 并行模式设计
论文的附录给出了对Prefill和Decode阶段的耗时建模方法,而在实验中,Prefill延迟模型为:
```
A + B*bs*l_in + C*sum_{i=1}^{bs} l_in_{i}^2
```
Decoding延迟模型为:
```
A + B*bs*l_in + C*bs
```
其中 bs 为batch size l_in 为输入的平均长度, l_in_{i}^2 表示第 i 个batch的请求平均输入长度的平方,通过采样实际执行时间,则可作为训练数据来分别拟合两个延迟模型的参数 A、B、C 。
总体寻优的思想也是比较清晰的。首先对不同并行策略下的耗时建立线性模型,再采集多组样本,对不同并行策略的线性模型进行拟合。值得一题的是,论文对Prefill和Decoding的耗时分别建立不同的模型,特别对于Decoding阶段又进一步区分了大Batch size和小Batch size两种场景下的建模。这或许可归因于第二节中对于Decoding阶段的分析,由于Decoding阶段的Batch size影响较大,区分建模能保证更高的精度。
模型建成后的寻优准则则是该论文与其他论文方法不同的地方。DistServe全篇更加强调对于TTFT和TPOT分别达到SLO的目标,因此寻优算法也遵从这一准则。算法如下:
![图5:寻优算法](https://pic4.zhimg.com/v2-abfeb73fb6e9abd120e44574e0f763b3_1440w.jpg)
截取自论文
前6行在做的就是遍历所有可能的并行模式,第7-13行开始利用拟合好的模型预测效果,筛选最佳方案,筛选标准是:(1). 在Prefill和Decoding均满足SLO,(2). 并行方案对应的最大支撑到达率大于输入到达率,对于每个并行方案的支撑到达率则采用二分查找法确定。最后在所有满足条件的方案中,找到需要GPU数量最少的方案输出。
论文同样给出了跨机的方法。跨机面临着缺少NVLink的高速连接,这时并行策略的性能则受制于机间通信带宽。不同于其他PD分离的方法,为了避免KV-Cache传输以及TP走机间通信,该论文在设置并行模式时,需要限制相同模型层的P和D需要在同一节点。示意图如下:
![图6:跨机并行模式](https://picx.zhimg.com/v2-eeac8ae66568b8cc9995008ca53543a7_1440w.jpg)
### 3.2 分离式推理
确定好并行模式后,就可以开始部署推理引擎了。
![图7:分离式推理架构](https://pic4.zhimg.com/v2-99d4df72385be3158ee6ffee9f385e0f_1440w.jpg)
截取自论文
DistServe的整体逻辑遵从"生产者-消费者"模式,总体Engine负责管理Prefill、Decoding引擎,两个引擎分别实现了各自的调度器,Prefill引擎为生产者,Decoding引擎为消费者,到达的请求会首先分配到Prefill调度器的等待队列,一旦当前Prefill实例的资源满足该请求所需,就会被调度到Prefill引擎执行该阶段的计算,执行完Prefill的请求会被存储到一个中转队列中,该队列中的请求会等待Decoding调度器的调度,一旦Decoding调度器检测到中转队列请求所需资源能够满足,就会被调度到Decoding引擎,进而执行Decoding阶段的计算。
## 4. Code结构
整个DistServe项目的代码可以分成两个部分。一个部分是项目基座,由C++和CUDA语言编写,用于定义推理服务中涉及到的模型计算、通信、资源开辟释放等,该项目名为SwiftTransformer,主要包含了对Transformer架构模型的优化算子等。第二部分则是论文重点内容所涉及的调度层,主要由Python编写。而在真正执行服务时,还有一层与用户交互的api层,同样由Python编写。
![图8:代码结构](https://pic2.zhimg.com/v2-210c79ec95b916b4ef068bbc2c4b00eb_1440w.jpg)
代码结构说明
## 5. 总结与讨论
该项目作为PD分离的经典工作,非常适合刚接触该技术的初学者进行了解和学习。DistServe的实践简单、没有涉及过多的其他优化技巧,适合作为验证PD分离这一单一技术性能的工作,代码可读性比较高。然而也是因为实践方式较为简单,特别是对于跨机的方案限制比较多。
另外,PD分离技术的使用场景也有相应的限制,例如至少需要两张GPU,因此考虑PD分离技术的场景通常需有相对充足的GPU资源,才能让该技术发挥出更大的空间。