文档(金鹏): 2026-08-06 章节 48 篇文章摘要归档
- 46 篇原文+摘要双文件归档(按 来源/作者 分层,复用本地归档 20 篇+新抓取 26 篇) - 即梦生成 9 组主题配图(大图+列表缩略图)存入 知识/金鹏/20260806/ - 章节重组为 9 个主题分组并挂接摘要引用
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# 1.5x提升:PD分离KV cache传输的实践经验
|
||||
|
||||
> **来源**:知乎专栏「LLM推理基础与框架」
|
||||
> **作者**:PD分离传输优化 HW/YN 联合团队(ky、zzy、LCAIZJ、CZ、hyh、lrj、zpb、dfq、fjw 等)
|
||||
> **发布日期**:2026-08-05
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/1946608360259577576
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
最近我们团队[1]在 vLLM 上开发了一种 KV cache 传输的 connector,实现了传输性能 __50%__[2]__的提升__,相关代码已全部开源。在过程中遇到的挑战/问题在这里进行一个分享,希望能给从事相关行业的读者带来些思考与借鉴。
|
||||
|
||||
基础知识参看上一篇:
|
||||
|
||||
## 1 问题模型分析
|
||||
|
||||
__总体需求__:LLM 的推理 PD 分离场景下,Prefill 实例要将计算好的 KV cache 传输给 Decode 实例进行后续运算,需要设计一种高效的传输机制保证推理性能。
|
||||
|
||||

|
||||
|
||||
KV cache 传输属于分布式模型数据传输的一种,所以网络传输中存在的带宽、时延、可靠性等问题都会遇到。KV cache 传输有自身特点,关注侧重点也有差异,主要看其对性能指标(TTFT/TPOT)的影响。如下大致梳理了 KV cache 传输中会遇到的问题:
|
||||
|
||||
| 类型 | 问题 | 举例 |
|
||||
| --- | --- | --- |
|
||||
| 数据 | 数据的类型 | torch.tensor、GPU/CPU tensor |
|
||||
| | 内存排布形态 | 按层排布、凑整排布 |
|
||||
| | attention 模块类型 | GQA/MLA/MHA |
|
||||
| 数据传输 | 传输通道 | TCP/RDMA |
|
||||
| | 链路数量 | FullMesh、异构传输; |
|
||||
| | 网络形态 | 跨节点、跨交换机,异构硬件 |
|
||||
| | 传输效率 | 及 |
|
||||
|
||||
## 参考
|
||||
|
||||
1. ^PD 分离传输优化 HW/YN 联合团队:ky、zzy、LCAIZJ、CZ、hyh、lrj、zpb、dfq、fjw 等
|
||||
2. ^性能参考基线为起始版本,平均提升基线为 0.5x,某些情况下可能会有一定损失
|
||||
|
||||
---
|
||||
|
||||
> **下载说明**:本文原文托管于知乎专栏,受知乎反爬虫/登录限制,本次抓取仅获得文章开头部分(目录、引言、问题模型分析小节及参考文献),正文后续章节(传输方案设计、优化手段、benchmark 数据等)未能完整获取。如需完整内容请访问原文链接登录阅读。
|
||||
@@ -0,0 +1,78 @@
|
||||
# 📊 文章摘要:1.5x提升:PD分离KV cache传输的实践经验
|
||||
|
||||
> **原文**:[2026-08-05_1.5x提升_PD分离KV_cache传输的实践经验.md](./2026-08-05_1.5x提升_PD分离KV_cache传输的实践经验.md)
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/1946608360259577576
|
||||
> **来源**:知乎专栏「LLM推理基础与框架」
|
||||
> **作者**:PD分离传输优化 HW/YN 联合团队(ky、zzy、LCAIZJ、CZ、hyh、lrj、zpb、dfq、fjw 等)
|
||||
> **发布日期**:2026-08-05
|
||||
> **摘要日期**:2026-08-06
|
||||
> **价值评级**:⭐⭐ 中
|
||||
|
||||
---
|
||||
|
||||
## 核心命题
|
||||
|
||||
> **KV传输提效50%** — 团队在 vLLM 上自研 KV cache 传输 connector 并将传输性能提升 50%、代码全部开源,本文分享传输优化的问题分类与实践经验。
|
||||
|
||||
---
|
||||
|
||||
## 文章概要
|
||||
|
||||
本文是 PD 分离传输优化 HW/YN 联合团队的一线实践分享:在 vLLM 上开发了 KV cache 传输 connector,实现传输性能 50% 的平均提升(以起始版本为基线,个别情况可能有损失),相关代码已全部开源。文章核心内容是 KV cache 传输的"问题模型分析"——从数据(张量类型、内存排布形态、attention 模块类型)与数据传输(通道、链路数量、网络形态、传输效率)两个维度系统梳理影响 TTFT/TPOT 的传输问题。这是排查传输瓶颈时实用的分类清单,但本文抓取仅获得开头部分,传输方案设计、优化手段与 benchmark 数据等核心章节未能获取,完整经验需访问原文阅读。
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **传输性能提升50%** — 团队开发的 KV cache 传输 connector 相比起始版本平均提升 0.5x,且代码全部开源,但"某些情况下可能会有一定损失"。`[分类: 共识]`(结论明确,细节待原文)
|
||||
2. **KV cache传输问题分类框架** — 从"数据"(类型/内存排布/attention 模块)与"数据传输"(通道/链路/网络形态/效率)两维建表归类,为 TTFT/TPOT 性能归因提供了可复用的排查清单。`[分类: 共识]`
|
||||
3. **性能指标导向的传输设计** — KV cache 传输虽属分布式模型数据传输,但关注点取决于其对 TTFT(首 Token 延迟)与 TPOT(单 Token 输出时间)的影响,设计取舍应围绕这两个指标展开。`[分类: 共识]`
|
||||
4. **工程经验开源化** — 联合团队将自研 connector 开源,反映 PD 分离生态中传输层组件正从各家私研走向社区共建。`[分类: 未探索方向]`
|
||||
|
||||
---
|
||||
|
||||
## 批判性分析
|
||||
|
||||
### 假设前提
|
||||
|
||||
作者假设 PD 分离场景中 Prefill 实例向 Decode 实例传输 KV cache 是推理性能的关键瓶颈,值得专门设计传输机制;并假设开源实现能在主流框架(vLLM)与常见硬件组合下通用复现其 50% 收益。
|
||||
|
||||
### 论据与逻辑
|
||||
|
||||
可获取部分只能证实"问题识别"层面,无法评估"50% 提升"的证据链——benchmark 场景、硬件基线、对比方法均未呈现;问题分类表本身完整度高,但"哪些问题对性能影响最大、如何解决"的逻辑主线全部落在未获取的正文中,论据链条严重缺失。
|
||||
|
||||
### 边界与局限
|
||||
|
||||
"50% 提升"以起始版本为基线、且自认个别情况有损失,说明收益高度依赖原始实现的粗糙程度与具体场景;受知乎反爬限制,本文摘要仅基于文章开头部分(引言、问题模型分析、参考文献),方案设计与实测数据未获,结论外推需谨慎。
|
||||
|
||||
---
|
||||
|
||||
## 可引用金句
|
||||
|
||||
> "最近我们团队在 vLLM 上开发了一种 KV cache 传输的 connector,实现了传输性能 50% 的提升,相关代码已全部开源。"
|
||||
|
||||
> "KV cache 传输属于分布式模型数据传输的一种,所以网络传输中存在的带宽、时延、可靠性等问题都会遇到。"
|
||||
|
||||
> "KV cache 传输有自身特点,关注侧重点也有差异,主要看其对性能指标(TTFT/TPOT)的影响。"
|
||||
|
||||
---
|
||||
|
||||
## 总体评价
|
||||
|
||||
**亮点**:
|
||||
- 问题分类框架(数据/传输两维)对排查 KV 传输瓶颈有直接实操价值,是全文最具可迁移性的产出
|
||||
- 50% 提升与开源动作值得关注,为同类团队提供了可验证的起点
|
||||
|
||||
**不足**:
|
||||
- 本次仅获取文章开头(约全文 20%),方案设计、优化手段、benchmark 数据全部缺失,无法完整评估
|
||||
- "50% 提升"缺少可核查的测试细节,基线定义(起始版本)使收益口径偏模糊
|
||||
|
||||
**适用场景**:vLLM 上实现 PD 分离、面临 KV cache 传输调优的推理工程团队;适合作为"传输问题清单"速查与开源代码入口(需登录知乎获取完整正文)。
|
||||
|
||||
**关联建议**:结合《LLM推理成本直降60%:PD分离在大模型商业化中的关键价值》中 vLLM KV Transfer 机制与 PyNCCL/Mooncake 后端选型阅读;传输层的量化收益可对照《异构智算中心分布式PD分离推理技术的探索与实践》中广域 KV 传输挑战。
|
||||
|
||||
---
|
||||
|
||||
## 配图
|
||||
|
||||

|
||||
@@ -0,0 +1,122 @@
|
||||
# 【推理】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. 调度低效:在相同GPU上进行不同状态的调度会造成decoding等待prefill的现象,并且GPU在进行decoding会导致资源低利用率;
|
||||
2. 资源和并行策略的耦合:两阶段的差异对于资源和并行策略的需求不同,相同GPU上部署不可避免的会导致两阶段资源和并行策略的共享。
|
||||
|
||||
至此,PD分离就成为了一种最为直接的解决思想。
|
||||
|
||||
## 2. P/D阶段特性分析
|
||||
|
||||
在正式提出算法前,论文对于P和D阶段的batch策略和并行方案进行了分析。对于batch策略,论文通过以下实验对比了两阶段的不同特点:
|
||||
|
||||

|
||||
|
||||
截取自论文
|
||||
|
||||
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的效果则更好,结合实验结果看更清楚:
|
||||
|
||||

|
||||
|
||||
截取自论文
|
||||
|
||||
这一实验结论对根据不同场景下设置并行模式起到了参考作用。而Decoding阶段的并行模式分析同理,TP可以降低延迟,但是过大的TP会引入过量通信,延迟降低的优势也就不再明显,PP虽不影响单个请求的执行时间,但可以加大吞吐。
|
||||
|
||||

|
||||
|
||||
截取自论文
|
||||
|
||||
不过对于这一部分的分析,本人也做了粗略的实验比较了一下两个阶段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的目标,因此寻优算法也遵从这一准则。算法如下:
|
||||
|
||||

|
||||
|
||||
截取自论文
|
||||
|
||||
前6行在做的就是遍历所有可能的并行模式,第7-13行开始利用拟合好的模型预测效果,筛选最佳方案,筛选标准是:(1). 在Prefill和Decoding均满足SLO,(2). 并行方案对应的最大支撑到达率大于输入到达率,对于每个并行方案的支撑到达率则采用二分查找法确定。最后在所有满足条件的方案中,找到需要GPU数量最少的方案输出。
|
||||
|
||||
论文同样给出了跨机的方法。跨机面临着缺少NVLink的高速连接,这时并行策略的性能则受制于机间通信带宽。不同于其他PD分离的方法,为了避免KV-Cache传输以及TP走机间通信,该论文在设置并行模式时,需要限制相同模型层的P和D需要在同一节点。示意图如下:
|
||||
|
||||

|
||||
|
||||
### 3.2 分离式推理
|
||||
|
||||
确定好并行模式后,就可以开始部署推理引擎了。
|
||||
|
||||

|
||||
|
||||
截取自论文
|
||||
|
||||
DistServe的整体逻辑遵从"生产者-消费者"模式,总体Engine负责管理Prefill、Decoding引擎,两个引擎分别实现了各自的调度器,Prefill引擎为生产者,Decoding引擎为消费者,到达的请求会首先分配到Prefill调度器的等待队列,一旦当前Prefill实例的资源满足该请求所需,就会被调度到Prefill引擎执行该阶段的计算,执行完Prefill的请求会被存储到一个中转队列中,该队列中的请求会等待Decoding调度器的调度,一旦Decoding调度器检测到中转队列请求所需资源能够满足,就会被调度到Decoding引擎,进而执行Decoding阶段的计算。
|
||||
|
||||
## 4. Code结构
|
||||
|
||||
整个DistServe项目的代码可以分成两个部分。一个部分是项目基座,由C++和CUDA语言编写,用于定义推理服务中涉及到的模型计算、通信、资源开辟释放等,该项目名为SwiftTransformer,主要包含了对Transformer架构模型的优化算子等。第二部分则是论文重点内容所涉及的调度层,主要由Python编写。而在真正执行服务时,还有一层与用户交互的api层,同样由Python编写。
|
||||
|
||||

|
||||
|
||||
代码结构说明
|
||||
|
||||
## 5. 总结与讨论
|
||||
|
||||
该项目作为PD分离的经典工作,非常适合刚接触该技术的初学者进行了解和学习。DistServe的实践简单、没有涉及过多的其他优化技巧,适合作为验证PD分离这一单一技术性能的工作,代码可读性比较高。然而也是因为实践方式较为简单,特别是对于跨机的方案限制比较多。
|
||||
|
||||
另外,PD分离技术的使用场景也有相应的限制,例如至少需要两张GPU,因此考虑PD分离技术的场景通常需有相对充足的GPU资源,才能让该技术发挥出更大的空间。
|
||||
@@ -0,0 +1,80 @@
|
||||
# 📊 文章摘要:【推理】PD分离的绝佳入门教程 —— DistServe
|
||||
|
||||
> **原文**:[2026-08-05_推理_PD分离的绝佳入门教程_DistServe.md](./2026-08-05_推理_PD分离的绝佳入门教程_DistServe.md)
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/19666783423
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:Zoe Lee
|
||||
> **发布日期**:2026-08-05
|
||||
> **摘要日期**:2026-08-06
|
||||
> **价值评级**:⭐⭐⭐ 高
|
||||
|
||||
---
|
||||
|
||||
## 核心命题
|
||||
|
||||
> **精读范本** — 以 DistServe(OSDI 2024)为样本讲透 PD 分离的动机、建模与寻优方法,并附代码复现的一手体会。
|
||||
|
||||
---
|
||||
|
||||
## 文章概要
|
||||
|
||||
作者精读 DistServe 论文并部署代码实验后整理的"玩后感":从混合 batch 中 prefill 与 decoding 相互拖累的实验证据出发说明 PD 分离动机;用 M/D/1 排队模型推导并行策略偏好(到达率低时 TP 更优、高时 PP 更优);讲解对 Prefill/Decode 分别建立延迟模型、以"满足 TTFT/TPOT 双 SLO + 支撑到达率 + GPU 数最少"为准则的寻优算法,以及跨机部署限制(相同模型层的 P/D 必须同节点)。价值在于把论文方法论讲得通俗透彻,且作者亲自复现并报告了与论文结论存在张力的个人观察。局限是作者自认初学,跨机细节阐述有限。
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **PD 分离动机有实验证据** — 混合 batch 中新增一个 prefill 请求会给 decoding 批处理带来显著的延迟危害(论文实验图),由此引出调度低效与资源/并行策略耦合两大问题 `[分类: 共识]`
|
||||
2. **batch 策略差异** — Prefill 吞吐随 batch size 的变化取决于输入文本长度,并非越大越好;增加 batch size 是 Decode 阶段避免低吞吐的好方法 `[分类: 共识]`
|
||||
3. **并行模式建模** — 用 M/D/1 排队模型推导 TTFT:到达率 R 小时 TP 效果更好,R 增加时 PP 更好;Decode 侧过大的 TP 会引入过量通信使延迟优势消失 `[分类: 范式突破]`
|
||||
4. **SLO 驱动的寻优算法** — 对 P/D 分别拟合延迟线性模型(Prefill 含输入长度二次项),遍历并行模式,筛选同时满足 TTFT/TPOT SLO 且支撑到达率达标的方案,取 GPU 数最少者 `[分类: 范式突破]`
|
||||
5. **跨机约束** — 为避免 KV Cache 跨机传输与 TP 走机间通信,设置并行模式时限制相同模型层的 P 和 D 在同一节点 `[分类: 未探索]`
|
||||
6. **生产者-消费者实现** — 总体 Engine 管理 Prefill 与 Decoding 两个引擎及各自调度器,prefill 产出经中转队列等待 Decoding 调度器消费;代码分 SwiftTransformer(C++/CUDA)基座与 Python 调度层两部分 `[分类: 共识]`
|
||||
7. **复现体会与论文结论的张力** — 作者粗略实验发现给定 P/D 卡数下并行策略的影响似乎不大,与论文强调并行模式寻优的价值形成对照(个人观察,尚需严格验证)`[分类: 争议]`
|
||||
|
||||
---
|
||||
|
||||
## 批判性分析
|
||||
|
||||
### 假设前提
|
||||
|
||||
假设读者熟悉 Transformer 推理与排队论基础;DistServe 的目标函数假设 TTFT/TPOT SLO 由用户显式给定,寻优结论依赖延迟模型对真实系统的拟合精度。
|
||||
|
||||
### 论据与逻辑
|
||||
|
||||
动机实验、延迟模型与寻优准则均忠实转述论文,并附作者部署代码的一手体会,论据扎实;作者对"并行策略影响不大"的观察明确标注为粗略实验,态度严谨,未以个人观察冒充论文结论。
|
||||
|
||||
### 边界与局限
|
||||
|
||||
作者明确指出 PD 分离至少需要两张 GPU、跨机方案限制较多,适合 GPU 资源充足的场景;论文方法面向"以 SLO 为中心"的在线服务目标,对离线批处理等非 SLO 场景不适用,且 DistServe 实现未涉及按层传输等后续优化技巧。
|
||||
|
||||
---
|
||||
|
||||
## 可引用金句
|
||||
|
||||
> "在相同GPU上进行不同状态的调度会造成decoding等待prefill的现象,并且GPU在进行decoding会导致资源低利用率"
|
||||
|
||||
> "Prefill阶段并不是batch size越大吞吐越大,吞吐随batch size的变化取决于输入文本的长度,因此在设置batch size时要考虑输入长度。"
|
||||
|
||||
---
|
||||
|
||||
## 总体评价
|
||||
|
||||
**亮点**:
|
||||
- 把 DistServe 的动机实验、M/D/1 建模、寻优准则讲得透彻清晰,入门友好
|
||||
- 有真实部署与复现的一手体会,并诚实报告与论文结论的张力
|
||||
- 代码结构拆解(SwiftTransformer + Python 调度层)便于读者自行"把玩"
|
||||
|
||||
**不足**:
|
||||
- 作者自认初学,跨机方案细节与性能数字讨论有限
|
||||
- 个人复现实验未给出具体数据,观察结论有待验证
|
||||
|
||||
**适用场景**:初次接触 PD 分离的工程师与学生作为入门导读;准备精读 DistServe 论文与复现其代码的读者。
|
||||
|
||||
**关联建议**:对照阅读 DistServe 论文原文与 GitHub 仓库(LLMServe/DistServe);与 akaihaoshuai 的实测结论(P/D 配比、cache 调度为核心)互相印证;进阶阅读 Mooncake(KVCache 中心化调度)与 NVIDIA Dynamo。
|
||||
|
||||
---
|
||||
|
||||
## 配图
|
||||
|
||||

|
||||
@@ -0,0 +1,580 @@
|
||||
# LLM关于PD分离的最新实测
|
||||
|
||||
> **来源**:知乎
|
||||
> **作者**:akaihaoshuai
|
||||
> **发布日期**:2025-06-22
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/1919794916504114120
|
||||
|
||||
---
|
||||
|
||||
LLM的PD分离在一年前就有一定的了解了,可以参考文章:[akaihaoshuai:LLM推理加速调研](https://zhuanlan.zhihu.com/p/699776257)中提到的DistServe多卡解耦prefill和decode优化耗时。后来也出现了Mooncake和deepseek的PD分离方案。根据prefill的计算密集型和decode的传输密集型特征进行解偶,可以使得效率最大化,
|
||||
现在vllm/sglang中都已经集成了一些PD分离的代码,最近正好有机会,深入了解并测试一下实际效果。
|
||||
|
||||
## 为什么要PD分离?
|
||||
首先要了解LLM的推理可以分为两个阶段
|
||||
- **Prefilling:**对输入的prompt,一次计算全部的kvcache,输出首token,此时的耗时为TTFT,通常在几百ms。
|
||||
- **Decoding:**根据计算好的kvcache,迭代式的生成每一个token。耗时为TBT,通常在10~20ms。
|
||||
画出LLM的推理过程示意图,可以看出,当prefilling和decoding在同一个batch中时,Prefilling操作会严重影响Decoding结果的输出效率。
|
||||
|
||||

|
||||
如果是PD分离架构
|
||||
|
||||

|
||||
从上图可以看出,PD分离可以提高decoding部分的效率。但是从TP2变成1P1D,prefilling的卡减少,大bs、长输入时会导致TTFT变长。
|
||||
|
||||
另外因为prefill的计算量大,decoder阶段的传输量大,因此PD分离可以对两个阶段使用不同类型的显卡,最大化性价比。
|
||||
|
||||

|
||||
因为相比A系列和H系列的卡,4090的算力可能在30%~50%左右,但是带宽只有10%不到,所以非常适合用于prefill阶段计算,性价比很高。
|
||||
|
||||
## 怎么进行PD分离?
|
||||
|
||||
> [PD分离-XpYd系统服务化](https://zhuanlan.zhihu.com/p/30619735151)
|
||||
[vLLM PD分离方案浅析](https://zhuanlan.zhihu.com/p/1889243870430201414)
|
||||
当前的server框架(比如[vllm](https://link.zhihu.com/?target=https%3A//github.com/vllm-project/vllm)、sglang)通常用于单机server。XpYd就是在这个基础上,再封装一层server代码,根据参数启动多个独立的server,分别标为prefill server和decoder server,管理不同server之间的cache调度。
|
||||
相同的vllm server怎么分为prefill server和decoder server呢?其实在启动参数上并没多大区别,启动两个server服务,所有的request首先发送到prefill server,并将max_tokens设为1。处理完成后将相同的request再输入decoder server,获取输出即可。那么这两个server自然就会一个只处理prefilling、一个只处理decoding了。
|
||||
|
||||
```
|
||||
# prefill server
|
||||
CUDA_VISIBLE_DEVICES='0' python3 -m vllm.entrypoints.openai.api_server \
|
||||
--model $MODEL_NAME \
|
||||
--port 8100 \
|
||||
--trust-remote-code \
|
||||
--enforce-eager \
|
||||
--kv-transfer-config \
|
||||
'{"kv_connector":"SharedStorageConnector","kv_role":"kv_both","kv_connector_extra_config": {"shared_storage_path": "local_storage"}}' &
|
||||
|
||||
# decoder server
|
||||
CUDA_VISIBLE_DEVICES='1' python3 -m vllm.entrypoints.openai.api_server \
|
||||
--model $MODEL_NAME \
|
||||
--port 8200 \
|
||||
--trust-remote-code \
|
||||
--enforce-eager \
|
||||
--kv-transfer-config \
|
||||
'{"kv_connector":"SharedStorageConnector","kv_role":"kv_both","kv_connector_extra_config": {"shared_storage_path": "local_storage"}}' &
|
||||
|
||||
# proxy server
|
||||
python3 disagg_pd_proxy_server.py &
|
||||
```
|
||||
其中disagg_pd_proxy_server.py可以参考代码:[https://github.com/vllm-project/vllm/blob/main/examples/online_serving/disaggregated_serving/disagg_proxy_demo.py](https://link.zhihu.com/?target=https%3A//github.com/vllm-project/vllm/blob/main/examples/online_serving/disaggregated_serving/disagg_proxy_demo.py)
|
||||
核心代码如下:
|
||||
|
||||
```
|
||||
@app.route('/v1/completions', methods=['POST'])
|
||||
async def handle_request():
|
||||
try:
|
||||
original_request_data = await request.get_json()
|
||||
prefill_request = original_request_data.copy()
|
||||
|
||||
# change max_tokens = 1 to let it only do prefill
|
||||
prefill_request['max_tokens'] = 1
|
||||
|
||||
# finish prefill
|
||||
async for _ in forward_request('http://localhost:8100/v1/completions',
|
||||
prefill_request):
|
||||
continue
|
||||
|
||||
# return decode
|
||||
generator = forward_request('http://localhost:8200/v1/completions',
|
||||
original_request_data)
|
||||
response = await make_response(generator)
|
||||
response.timeout = None
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
print("Error occurred in disagg prefill proxy server")
|
||||
```
|
||||
当然,只是上面的简单修改还不够,vllm中的代码也要修改,要将prefill server中计算的kvcache发送到decoder server。
|
||||
对于vllm server来说,每次推理前,检查当前输入的token_ids有没有处理过的kv cache缓存,如果有,则可以直接复用,即decoding处理。如果没有,则进行prefilling处理,并将kv cache保存,保存的key需要和token_ids相关。
|
||||
[https://github.com/vllm-project/vllm/blob/main/vllm/v1/worker/gpu_model_runner.py](https://link.zhihu.com/?target=https%3A//github.com/vllm-project/vllm/blob/main/vllm/v1/worker/gpu_model_runner.py)
|
||||
|
||||

|
||||
基本的PD分离逻辑基本介绍完了,当初看的时候感觉是个很复杂的工程,现在用来也没有多麻烦(当然是vllm和多位大神代码集成的好,而且实际在用的话还需要很多的优化)
|
||||
|
||||
到这里大家就知道了,**PD分离的核心其实在于cache的调度。**
|
||||
|
||||
## [vllm](https://link.zhihu.com/?target=https%3A//github.com/vllm-project/vllm)的PD分离
|
||||
[vllm](https://link.zhihu.com/?target=https%3A//github.com/vllm-project/vllm)0.9.1版本,kv cache调度器支持的KVconnector类型如下。
|
||||
|
||||

|
||||
下面只介绍v1版本的几种PD分离
|
||||
|
||||
### SharedStorageConnector
|
||||
[https://github.com/vllm-project/vllm/blob/main/vllm/distributed/kv_transfer/kv_connector/v1/shared_storage_connector.py](https://link.zhihu.com/?target=https%3A//github.com/vllm-project/vllm/blob/main/vllm/distributed/kv_transfer/kv_connector/v1/shared_storage_connector.py)
|
||||
从代码中可以看出主要包含save_kv_layer和start_load_kv两个函数。
|
||||
|
||||

|
||||
- prefill阶段,会将计算的kvcache通过save_kv_layer函数保存到本地文件夹中。
|
||||
- decoder阶段,会通过start_load_kv函数从本地文件夹中读取kvcache。
|
||||
|
||||
测试发现,代码中目前只支持1P1D,且prefill_tp_size=decoder_tp_size=1。
|
||||
若要支持prefill_tp_size != decoder_tp_size,则需要修改代码:在save_kv_layer中增加rank标记,保证多rank同时保存时不互相覆盖。在start_load_kv函数中增加读取多个rank读取cache,并根据当前server的tp数量进行cache拆分的逻辑。
|
||||
**分析:**从代码中可以看出,在prefill和decoder之间有文件保存和读取操作,会大幅影响结果耗时。
|
||||
|
||||
### P2pNcclConnector
|
||||
从代码中可以看出,P2pNcclConnector相比于SharedStorageConnector,就是把safetensors save/load操作换成了nccl的send和reciver操作。
|
||||
|
||||

|
||||
NCCL(**NVIDIA Collective Communications Library**)是 NVIDIA 提供的一个用于多 GPU 和多节点之间高效通信的库。它主要用于深度学习和高性能计算(HPC),支持常见的集合通信操作,如 `AllReduce`、`Broadcast`、`Reduce`、`Scatter` 和 `Gather` 等。
|
||||
- **特点**:
|
||||
- 高性能:针对 NVIDIA GPU 进行优化,支持 PCIe、NVLink 和 InfiniBand。
|
||||
- 多节点扩展:支持跨多个节点的 GPU 通信。
|
||||
- 支持多种数据类型和通信模式(LL、LL128、SIMPLE 协议等)。
|
||||
- 可配置参数(如 `NCCL_PROTO`, `NCCL_ALGO`, `NCCL_MAX_NCHANNELS`)以优化性能。
|
||||
|
||||
使用NCCl在GPU之间直接处理数据,大幅降低了数据传输耗时。
|
||||
|
||||

|
||||
NCCL 负责 GPU 间的数据传输,而 ZMQ 仅用于控制信道(metadata 交换)。两者配合使用,但并不直接通过 ZMQ 传输张量数据。
|
||||
|
||||
```
|
||||
# 在 P2pNcclEngine 中:
|
||||
self.nccl = NCCLLibrary(library_path) # 初始化 NCCL 库
|
||||
self._create_connect(remote_address) # 使用 ZMQ 发起连接请求,并初始化 NCCL Comm
|
||||
self._send(comm, tensor, dst, stream) # 实际调用 ncclSend 进行 GPU 数据传输
|
||||
```
|
||||
|
||||
### LMCacheConnectorV1——[LMCache](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache)
|
||||
|
||||
> [https://github.com/LMCache/LMCache](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache)
|
||||
封装了一层[LMCache](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache)调用逻辑。
|
||||
|
||||

|
||||
[LMCache](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache)是一个针对vllm的cache复用框架。**主要优点**
|
||||
- 减少推理时间:通过重用缓存的 KV 张量消除冗余计算(通过CPU以及磁盘缓存,可以保存更多的cache)
|
||||
- 更高的吞吐量:处理处理过的文本,节省 GPU 周期
|
||||
- 内存效率:分层存储系统优化 GPU、CPU 和磁盘的内存使用率
|
||||
- 非前缀缓存:支持缓存任何文本片段,而不仅仅是前缀(decoding过程的cache也可以全部保存)
|
||||
- 框架集成:与 vLLM 服务堆栈无缝集成(推理直接调用vllm,保存vllm的cache)
|
||||
|
||||
入口[https://github.com/LMCache/LMCache/tree/dev/lmcache/integration/vllm/vllm_v1_adapter.py](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache/tree/dev/lmcache/integration/vllm/vllm_v1_adapter.py)的LMCacheConnectorV1Impl类。
|
||||
根据类型,选择创建SCHEDULER还是SERVER WORKER
|
||||
|
||||

|
||||
|
||||
在vllm中的调用过程
|
||||
|
||||

|
||||
|
||||
prefill阶段调用流程:save_kv_layer -> self._lmcache_engine.save_kv_layer -> self.lmcache_engine.store_layer
|
||||
|
||||

|
||||
decoder阶段调用流程:start_load_kv -> self._lmcache_engine.start_load_kv -> self.lmcache_engine.retrieve_layer
|
||||
|
||||

|
||||
|
||||
可以看出storage_manager是存储管理。gpu_connector是负责数据传输。
|
||||
|
||||
StorageManager包含storage_backends,主要支持NixlBackend、LocalCPUBackend、LocalDiskBackend和RemoteBackend等类。其中分别是通过本地GPU、本地CPU、本地disk和跨结点传输数据。(Nixl是nvidia开源的gpu传输技术,后面会单独开一节详细介绍)跨结点传输包含了mooncake实现。
|
||||
|
||||

|
||||
|
||||
vllm_Connector支持下面几种,外部支持调用的是最后三种。
|
||||
|
||||

|
||||
|
||||
Connector总结对比
|
||||
|
||||

|
||||
|
||||
KV 缓存请求流程和数据处理管道
|
||||
|
||||

|
||||
[LMCache](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache)还有一个enable_blending功能,可以支持kvcache的位置编码解耦,从而能够复用非前缀缓存,进一步提高推理效率。
|
||||
|
||||

|
||||
|
||||
### NixlConnector——[nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)
|
||||
NixlConnector中使用了nvidia-smi的[nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)库进行通信,其他用法和P2pNcclConnector没有什么区别。
|
||||
|
||||

|
||||
[nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)的具体内容以及[nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)和nccl的比较放到下面的[dynamo](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/dynamo)一节中详细讲解。
|
||||
|
||||
## sglang的PD分离
|
||||
|
||||
> [Deploying DeepSeek with PD Disaggregation and Large-scale Expert Parallelism on 96 H100 GPUs](https://link.zhihu.com/?target=https%3A//lmsys.org/blog/2025-05-05-large-scale-ep/%23prefill-and-decode-disaggregation)
|
||||
[https://github.com/sgl-project/sglang/issues/4655](https://link.zhihu.com/?target=https%3A//github.com/sgl-project/sglang/issues/4655)
|
||||
[https://docs.sglang.ai/backend/pd_disaggregation.html](https://link.zhihu.com/?target=https%3A//docs.sglang.ai/backend/pd_disaggregation.html)
|
||||
收到输入请求后,工作流程如下:
|
||||
|
||||
1. 预填充服务器和解码服务器通过握手配对,分别建立本地发送方和接收方。
|
||||
|
||||
2. 解码服务器预先分配 KV 缓存,向预填充服务器发出信号,开始模型前向传递并计算 KV 缓存。
|
||||
|
||||
3. 一旦计算完成,数据就会传输到解码服务器,由其处理迭代令牌生成。
|
||||
|
||||

|
||||
|
||||
### github代码详解
|
||||
代码框架如下
|
||||
|
||||

|
||||
|
||||
Engine中创建Scheduler。
|
||||
|
||||

|
||||
PrefillBootstrapQueue和DecodePreallocQueue中都会创建kv_manager对kv cahce进行管理
|
||||
|
||||

|
||||
支持mooncake和nixl后端。
|
||||
|
||||

|
||||
|
||||

|
||||
状态值
|
||||
|
||||

|
||||
|
||||
调用/v1/chat/completions接口时,会走到generate接口 --> _global_state.tokenizer_manager.generate_request() --> self._send_one_request() --> self.send_to_scheduler.send_pyobj(),将request发送到两个server的scheduler。
|
||||
|
||||

|
||||
|
||||
### prefill server处理流程
|
||||
|
||||

|
||||
1、在schedule中调用handle_generate_request()->_add_request_to_queue()处理新的request。
|
||||
2、在_add_request_to_queue()中调用调用PrefillBootstrapQueue().add()将 request添加到queue中。并添加到schedule.waiting_queue中。
|
||||
|
||||

|
||||
3、后台运行的event_loop_normal_disagg_prefill()检测到queue中包含未处理的req,进行处理。
|
||||
|
||||

|
||||
4、在process_batch_result_disagg_prefill()中通过disagg_kv_sender发送处理过的kv cache。
|
||||
|
||||

|
||||
|
||||
### decode server处理流程
|
||||
|
||||

|
||||
1、在schedule中调用handle_generate_request()->_add_request_to_queue()处理新收到的request。
|
||||
2、在_add_request_to_queue()中调用调用DecodePreallocQueue().add()将 request添加到queue中。并添加到schedule.waiting_queue中。
|
||||
3、后台运行的event_loop_overlap_disagg_decode() --> process_decode_queue() 检测到queue中包含未处理的req,进行处理。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
其中MooncakeKVManager使用的[Mooncake](https://link.zhihu.com/?target=https%3A//github.com/kvcache-ai/Mooncake)开源项目,NixlKVManager使用的[nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)开源项目
|
||||
|
||||
## [Mooncake](https://link.zhihu.com/?target=https%3A//github.com/kvcache-ai/Mooncake)
|
||||
|
||||
> [Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving](https://link.zhihu.com/?target=https%3A//arxiv.org/abs/2407.00079)
|
||||
[https://github.com/kvcache-ai/Mooncake](https://link.zhihu.com/?target=https%3A//github.com/kvcache-ai/Mooncake)
|
||||
[Mooncake 最新进展:SGLang 和 LMCache 基于 Mooncake 实现高效 PD 分离框架](https://zhuanlan.zhihu.com/p/1906034699358437813)
|
||||
[Mooncake (1): 在月之暗面做月饼,Kimi 以 KVCache 为中心的分离式推理架构](https://zhuanlan.zhihu.com/p/705754254)
|
||||
[Mooncake阅读笔记:深入学习以Cache为中心的调度思想,谱写LLM服务降本增效新篇章](https://zhuanlan.zhihu.com/p/706097807)
|
||||
[从MoonCake看大模型推理的PD分离,太快会扯到蛋吗?](https://zhuanlan.zhihu.com/p/8056351077)
|
||||
论文介绍了Mooncake,这是一个为LLM服务设计的KVCache中心分布式架构,旨在高效处理高并发请求并满足SLO。Mooncake通过分离预填充和解码集群,利用GPU集群中的闲置资源构建分布式KVCache,并采用KVCache中心调度器来优化请求调度。
|
||||
|
||||

|
||||
|
||||
### arxiv
|
||||
Mooncake 采用分解式架构,不仅将预填充节点与解码节点分离,还将 GPU 集群的 CPU、DRAM、SSD 和 RDMA 资源分组,以实现分解式 KVCache。这种分解式缓存能够充分利用未充分利用的资源,提供充足的缓存容量和传输带宽,从而实现高效的近 GPU 前缀缓存,而无需额外成本。
|
||||
|
||||

|
||||
|
||||
论文详细介绍了Mooncake架构的设计,该架构以KVCache为中心,通过分离预填充和解码集群,并利用GPU集群中未充分利用的CPU、DRAM和SSD资源实现KVCache的分布式缓存。具体方法如下:
|
||||
- **分离预填充和解码集群**:预填充阶段主要处理输入令牌的并行计算,而解码阶段则逐个处理输出令牌。通过分离这两个阶段,可以针对它们不同的计算特性进行优化。
|
||||
- **分布式KVCache设计**:利用GPU集群中的闲置资源构建分布式KVCache,提高缓存容量和传输带宽,实现高效的近GPU前缀缓存。
|
||||
- **KVCache中心调度器**:核心是KVCache中心调度器(Conductor),它负责根据当前KVCache分布和工作负载调度请求,并根据需要复制或交换KVCache块。
|
||||
- **请求处理流程**:对于每个请求,Conductor选择一对预填充和解码实例,并按照以下步骤调度请求:
|
||||
|
||||

|
||||
- **KVCache重用**:预填充实例根据请求的前缀缓存块ID从远程CPU内存加载KVCache到GPU内存,以启动请求处理。
|
||||
- **增量预填充**:预填充实例完成预填充阶段,并将新生成的增量KVCache存储回CPU内存。如果未缓存的输入令牌数量超过一定阈值,则将预填充阶段拆分为多个块,并以流水线方式执行。
|
||||
- **KVCache传输**:使用基于RDMA的Messenger服务在节点间管理和传输这些缓存,将模型各层生成的KVCache流式传输到目标解码节点的CPU内存,减少等待时间。
|
||||
- **解码**:解码节点在接收到所有KVCache后,将请求加入下一批次进行连续批处理。Conductor根据当前负载预选解码节点,以确保不违反TBT SLO。
|
||||
- **缓存感知调度**:在预填充阶段,调度器会根据请求的前缀缓存匹配长度和实例负载选择预填充实例,以平衡缓存重用和负载均衡。
|
||||
- **缓存负载均衡**:通过自动复制热点KVCache块,将它们分布到多个机器上,以避免缓存获取拥塞。
|
||||
|
||||
统计了线上的输入和输出:平均输入长度为 7,590 个 token,平均输出长度为 182 个 token。
|
||||
比较了三种缓存策略:LRU、LFU 和 LengthAwareCache。
|
||||
|
||||

|
||||
将缓存容量从 1,000 个块增加到 50,000 个块,缓存命中率会从 30% 提升到 50%。继续增加则没有明显改善。
|
||||
|
||||
- **CPP(chunked pipeline parallelism)**
|
||||
输入越来越长,需要做chunk_prefill,继续提升:对于每个请求,其输入令牌会被划分为多个块,每个块的长度不超过prefill_chunk。同一请求的不同块可以由不同的节点同时处理,从而实现并行处理并减少 TTFT。
|
||||
|
||||
- **Layer-wise Prefill**
|
||||
理论上,如果一个请求的 KVCache 大小为S,处理时间为T,则其占用成本为S∗T。如果在分块预填充中,将请求分块处理,并将每个分块的处理与其他解码请求内联,则T会增加,导致占用成本更大。
|
||||
|
||||

|
||||
不同请求长度的 KVCache 存储延迟
|
||||
|
||||
- **Prefill Global Scheduling**
|
||||
在 Mooncake 中,预填充实例的选择不仅考虑负载,还考虑前缀缓存命中长度以及可重用 KVCache 块的分布。
|
||||
对于每个新请求,其输入令牌会被分成多个块,并为每个块计算一个哈希键。这涉及生成一个块中令牌的哈希键,该哈希键与前一个块的哈希键(如果可用)连接。然后将请求的块键与每个预填充实例的缓存键逐一进行比较,以确定前缀匹配长度 (prefix_len)。
|
||||
利用这些匹配信息,Conductor 会根据请求长度和prefix_len(因实例而异)估算相应的执行时间。然后,它会添加该请求的预计等待时间,以获得该实例的 TTFT。最后,Conductor 将请求分配给 TTFT 最短的实例,并相应地更新该实例的缓存和队列时间。
|
||||
|
||||
- **Cache Load Balancing**
|
||||
每台预填服务器都管理着自己的一组本地前缀缓存。这些缓存的使用频率差异很大。
|
||||
解决此 KVCache 调度问题的一个简单解决方案是收集每个块的全局使用情况,使用预测模型预测其未来使用情况,并据此做出调度决策。
|
||||
如果预估的额外预填充时间短于传输时间,则指挥者会将缓存位置和请求转发到备用实例。此实例会主动从持有者处检索 KVCache 并将其存储在本地。更重要的是,我们倾向于在最佳远程前缀匹配长度不大于当前本地可重用前缀乘以阈值1这两种策略不仅可以减少请求的预填充时间,还可以促进热点缓存的自动复制。
|
||||
|
||||

|
||||
|
||||
- **Early Rejection**
|
||||
预填充或解码实例的负载并不能准确反映系统实际处理的请求数量。这种差异是由于单个请求的预填充和解码实例调度之间存在时间差造成的。
|
||||
为了解决这个问题,很自然地需要将解码实例的负载评估提前到预填充阶段开始之前。请求到达后,Conductor 会根据预填充池和解码池中较大的负载来评估是否接受该请求。早期拒绝 (Early Rejection) 可以显著减少因被拒绝请求而导致的无效计算,并增强负载均衡。
|
||||
|
||||

|
||||
经过进一步研究,我们发现这种负载波动问题的根源在于预测解码负载与实际执行之间的时间滞后。基于当前解码负载的调度本质上存在延迟。
|
||||
|
||||

|
||||
|
||||
- **效果测试**
|
||||
每个node配置8 块 NVIDIA-A800-SXM4-80GB GPU,通过 NVLINK 连接;配备 RDMA 网卡,节点间互联带宽最高可达 800Gbps。
|
||||
|
||||

|
||||
Mooncake-[3P+1D] 的吞吐量分别比 vLLM-[4M] 提高了 20% 和 40%,同时满足服务水平目标 (SLO)。
|
||||
尽管 Mooncake-[2P+2D] 拥有较低的 TBT 延迟,但在 TTFT 指标上的表现不如 Mooncake-[3P+1D] 和 vLLM-[4M]。
|
||||
|
||||
### github代码框架
|
||||
Mooncake 由三个主要组件组成,它们协同工作以实现高效的分解 LLM 服务:Transfer Engine、Mooncake Store和P2P Store
|
||||
|
||||
- **Transfer Engine**
|
||||
它通过调度程序架构支持 TCP、RDMA (InfiniBand/RoCEv2)、NVLink 和 NVMe-oF 协议。提供跨多个协议和存储设备的统一、高性能数据传输。
|
||||
|
||||
1. **多协议支持**:根据拓扑和可用性自动选择协议
|
||||
|
||||
2. **带宽聚合**:利用多个 RDMA NIC 设备来提高吞吐量
|
||||
|
||||
3. **拓扑感知路由**:根据 NUMA 关联性和设备位置选择最佳传输路径
|
||||
|
||||
4. **容错:**出现网络错误时自动故障转移到替代路径
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- **Mooncake Store**
|
||||
专为 LLM 推理工作负载设计的分布式 KVCache 存储引擎
|
||||
|
||||
1. **多副本支持**:存储同一对象的多个副本,以缓解访问热点
|
||||
|
||||
2. **并行 I/O**:支持大型对象的数据条带化和并行传输
|
||||
|
||||
3. **内存管理**:集成以实现高效的内存段分配`BufferAllocatorManager`
|
||||
|
||||
4. **协调**:用于元数据管理和对象生命周期控制`MasterService`
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- **P2P Store:**为 checkpoint 转移、模型权重分配等场景提供去中心化的临时对象共享。
|
||||
|
||||

|
||||
|
||||
## Dynamo/[nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)
|
||||
|
||||
> [https://github.com/ai-dynamo/dynamo](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/dynamo)
|
||||
[怎么看英伟达GTC新发布的推理框架Dynamo](https://zhuanlan.zhihu.com/p/31583638702)
|
||||
[Nvidia Dynamo 详解一](https://link.zhihu.com/?target=https%3A//ata.atatech.org/articles/11020396057%3Fspm%3Data.21736010.0.0.675927713lFoan)
|
||||
|
||||

|
||||
Dynamo 与推理引擎无关,支持 TRT-LLM、vLLM、SGLang 等,并捕获 LLM 特定的功能,例如:
|
||||
- **分解预填充和解码推理**- 最大化 GPU 吞吐量并促进吞吐量和延迟之间的权衡。
|
||||
- **动态 GPU 调度**- 根据波动的需求优化性能。
|
||||
- **LLM 感知请求路由**- 消除不必要的 KV 缓存重新计算。
|
||||
- **加速数据传输**- 使用 NIXL 减少推理响应时间。
|
||||
- **KV 缓存卸载**- 利用多个内存层次结构实现更高的系统吞吐量。
|
||||
|
||||

|
||||
Dynamo 采用了 NIXL 技术,这项技术旨在通过减少同步和智能批处理来加快传输速度。为了实现最佳性能和可扩展性,Dynamo 充分利用了 Rust 和 Python 的优势。。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### [nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)
|
||||
|
||||
> [https://github.com/ai-dynamo/nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)
|
||||
NIXL 解决了分布式推理工作负载面临的复杂挑战,尤其是在网络和通信方面。这些挑战包括高性能要求、跨内存和存储的异构数据路径以及动态扩展的需求。NIXL 通过支持多个后端插件(如 UCX、GDS 和其他协议)的多功能 API,跨内存类型(HBM、DRAM、本地/远程 SSD)和存储系统提供高带宽、低延迟的点对点数据传输和统一抽象。
|
||||
|
||||

|
||||
NIXL 通过内存部分抽象出各种内存类型,允许跨异构系统进行统一的内存处理。Memory 部分表示可访问以进行数据传输的已注册内存段。
|
||||
|
||||
| 内存类型 | 描述 |
|
||||
| --- | --- |
|
||||
| DRAM_SEG | 系统内存 (RAM) |
|
||||
| VRAM_SEG | GPU 内存 (VRAM) |
|
||||
| FILE_SEG | 文件存储 |
|
||||
| BLK_SEG | 块存储设备 |
|
||||
| OBJ_SEG | 对象存储 |
|
||||
NIXL 目前支持以下后端技术:
|
||||
|
||||
1. **UCX (Unified Communication X):**用于高性能网络的通信框架。
|
||||
|
||||
2. **GDS (GPUDirect Storage):**NVIDIA Magnum IO GPUDirect Storage,用于在 GPU 内存和存储之间直接传输数据。
|
||||
|
||||
3. **UCX_MO (UCX Memory Operations):**UCX 的扩展,专注于内存作。
|
||||
|
||||
### [gdrcopy](https://link.zhihu.com/?target=https%3A//github.com/NVIDIA/gdrcopy)
|
||||
GDRCopy 是一个基于 NVIDIA GPUDirect RDMA 技术构建的低延迟 GPU 内存复制库。它支持从 CPU 直接访问 GPU 内存,与传统的 CUDA 内存操作相比,数据传输延迟显著降低。
|
||||
- **非常低的开销**:GDRCopy 操作由 CPU 驱动,典型操作的开销仅为 0.1-0.2μs,而传统操作的开销为 6-7μs `cudaMemcpy`。
|
||||
- **高带宽**:在支持的平台上,写入操作(主机到设备)可以达到 6-8 GB/s。
|
||||
- **直接内存访问**:应用程序可以直接读取和写入 GPU 内存,而无需中间复制。
|
||||
|
||||
## 测试脚本
|
||||
### vllm
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
# This file demonstrates the example usage of disaggregated prefilling
|
||||
# We will launch 2 vllm instances (1 for prefill and 1 for decode),
|
||||
# and then transfer the KV cache between them.
|
||||
|
||||
set -xe
|
||||
|
||||
MODEL_NAME="/opt/llm/input/pretrain/Qwen--QwQ-32B"
|
||||
MAX_MODEL_LEN=32768
|
||||
GPU_MEMORY_UTILIZATION=0.95
|
||||
gpu_id_prefill="0,1"
|
||||
gpu_id_decoder="2,3"
|
||||
kv_cache_type="SharedStorageConnector" # SharedStorageConnector/ LMCacheConnectorV1 / NixlConnector
|
||||
|
||||
# Trap the SIGINT signal (triggered by Ctrl+C)
|
||||
trap 'cleanup' INT
|
||||
|
||||
export VLLM_HOST_IP=$(hostname -I | awk '{print $1}')
|
||||
|
||||
# a function that waits vLLM server to start
|
||||
wait_for_server() {
|
||||
local port=$1
|
||||
timeout 1200 bash -c "
|
||||
until curl -s localhost:${port}/v1/completions > /dev/null; do
|
||||
sleep 1
|
||||
done" && return 0 || return 1
|
||||
}
|
||||
|
||||
# You can also adjust --kv-ip and --kv-port for distributed inference.
|
||||
gpu_count_prefill=$(echo "$gpu_id_prefill" | tr ',' '\n' | wc -l)
|
||||
gpu_count_decode=$(echo "$gpu_id_decoder" | tr ',' '\n' | wc -l)
|
||||
|
||||
echo "Using LMCacheConnectorV1 for kv cache"
|
||||
# prefilling instance, which is the KV producer
|
||||
CUDA_VISIBLE_DEVICES=$gpu_id_prefill python3 -m vllm.entrypoints.openai.api_server \
|
||||
--model $MODEL_NAME \
|
||||
--disable-log-requests \
|
||||
--port 8100 \
|
||||
--max-model-len $MAX_MODEL_LEN \
|
||||
--gpu-memory-utilization $GPU_MEMORY_UTILIZATION \
|
||||
--trust-remote-code \
|
||||
--enforce-eager \
|
||||
--tensor-parallel-size $gpu_count_prefill \
|
||||
--kv-transfer-config \
|
||||
'{"kv_connector":"LMCacheConnectorV1","kv_role":"kv_producer","kv_connector_extra_config": {"discard_partial_chunks": false, "lmcache_rpc_port": "producer1"}}' &
|
||||
|
||||
CUDA_VISIBLE_DEVICES=$gpu_id_decoder python3 -m vllm.entrypoints.openai.api_server \
|
||||
--model $MODEL_NAME \
|
||||
--disable-log-requests \
|
||||
--port 8200 \
|
||||
--max-model-len $MAX_MODEL_LEN \
|
||||
--gpu-memory-utilization $GPU_MEMORY_UTILIZATION \
|
||||
--trust-remote-code \
|
||||
--enforce-eager \
|
||||
--tensor-parallel-size $gpu_count_decode \
|
||||
--kv-transfer-config \
|
||||
'{"kv_connector":"LMCacheConnectorV1","kv_role":"kv_consumer","kv_connector_extra_config": {"discard_partial_chunks": false, "lmcache_rpc_port": "consumer1"}}' &
|
||||
|
||||
# wait until prefill and decode instances are ready
|
||||
wait_for_server 8100
|
||||
wait_for_server 8200
|
||||
|
||||
python3 disagg_pd_proxy_server.py &
|
||||
|
||||
output2=$(curl -X POST -s http://localhost:8000/v1/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "'$MODEL_NAME'",
|
||||
"prompt": "hello. Santa Clara is a",
|
||||
"max_tokens": 10,
|
||||
"temperature": 0
|
||||
}')
|
||||
```
|
||||
lmcache最好从官方docker中安装
|
||||
|
||||
### [sglang](https://link.zhihu.com/?target=https%3A//github.com/sgl-project/sglang)
|
||||
参考:[sglang Dense LLM PD分离部署](https://link.zhihu.com/?target=https%3A//blog.csdn.net/u013701860/article/details/147745303)
|
||||
|
||||

|
||||
同一个PD组中,P/D的tp_size需要相同,可以设置多个P或者多个D。
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
MODEL_NAME="Qwen/Qwen3-0.6B"
|
||||
MAX_MODEL_LEN=32768
|
||||
gpu_id_prefill=0,1
|
||||
gpu_id_decoder=2,3
|
||||
GPU_MEMORY_UTILIZATION=0.95
|
||||
|
||||
# prefill
|
||||
echo "async start prefill server."
|
||||
CUDA_VISIBLE_DEVICES=$gpu_id_prefill python3 -m sglang.launch_server --model-path $MODEL_NAME \
|
||||
--disaggregation-mode prefill \
|
||||
--context-length $MAX_MODEL_LEN \
|
||||
--tp-size $gpu_count_prefill \
|
||||
--disable-radix-cache \
|
||||
--mem-fraction-static $GPU_MEMORY_UTILIZATION \
|
||||
--disaggregation-transfer-backend $disaggregation_transfer_backend \
|
||||
--trust-remote-code \
|
||||
--page-size 16 \
|
||||
--port 8100 &
|
||||
|
||||
# decoder
|
||||
echo "async start decoder server."
|
||||
CUDA_VISIBLE_DEVICES=$gpu_id_decoder python3 -m sglang.launch_server --model-path $MODEL_NAME \
|
||||
--disaggregation-mode decode \
|
||||
--context-length $MAX_MODEL_LEN \
|
||||
--tp-size $gpu_count_decoder \
|
||||
--disable-radix-cache \
|
||||
--mem-fraction-static $GPU_MEMORY_UTILIZATION \
|
||||
--disaggregation-transfer-backend $disaggregation_transfer_backend \
|
||||
--trust-remote-code \
|
||||
--page-size 16 \
|
||||
--port 8200 &
|
||||
|
||||
echo "start schedule server."
|
||||
python3 -m sglang.srt.disaggregation.mini_lb \
|
||||
--prefill http://localhost:8100 --decode http://localhost:8200 --host 0.0.0.0 --port 8002 &
|
||||
|
||||
# 多个prefill和decoder node 链接:https://blog.csdn.net/u013701860/article/details/147745303
|
||||
```
|
||||
|
||||
## 结论
|
||||
1、实测对于超长上下文+大模型+高并发,PD分离可以始终保持TBT在一个很稳定的状态,吞吐量可以提升20%~50%不等。一般来说,至少也要输入>8k、输出>100、并发>10、模型大于32B左右,才有一些效果。
|
||||
2、PD分离优化的是TBT,对TTFT没有提升。
|
||||
3、PD分离时,如果prefill server少太多,可能会导致prefill阶段的计算能力不够,从而使TTFT变慢。因此Pod4改成3P1D差不多,2P2D一般不太行。但是实际上prefill只有一次,而decoder要很多遍,因此1P2D的配置可以更好的提高整体serve的资源利用率。
|
||||
4、PD分离时的prefill tp_size和decoding的tp_size可以不同。server数量也可以不同。server数量可以根据流量动态的增加和减少。
|
||||
5、kv cache传输人有GPU、CPU和disk等多种方式,其中GPU最快,基本可以保持原本的TTFT,其他都会导致TTFT变慢。NCCL需要在初始化时就确定全部的GPU,因此不适合于规模动态调整的PD分离场景,且不支持cpu和disk传输,Mooncake在此基础上进行了统一,支持多种传输方式。Dynamo也重新封装了一层nixl传输协议。
|
||||
6、request调度是PD分离的核心,不能只考虑负载均衡,还要考虑cache复用率、显存剩余空间等。
|
||||
7、PD分离后,会存在Prefill server宽带利用率低,decoder server的GPU利用率低的情况。
|
||||
|
||||
> [NVIDIA Dynamo的PD分离有问题?我们提出的大模型推理系统"肾上腺素",是良药!](https://zhuanlan.zhihu.com/p/1888519961636487325)
|
||||
8、PD分离适用于bs较大、输入、输出都比较长的场景。普通场景没必要折腾。能单卡跑的没必要多卡,能单机承载的没必要多机。
|
||||
9、PD分离优势——异构框架:计算性能极强但传输带宽较低的GPU进行prefill,使用计算能力一般但传输带宽很高的GPU进行decoding。这样才能更好的发挥优势。
|
||||
|
||||
## 参考文章
|
||||
[PD分离-XpYd系统服务化](https://zhuanlan.zhihu.com/p/30619735151)
|
||||
[vLLM PD分离方案浅析](https://zhuanlan.zhihu.com/p/1889243870430201414)
|
||||
[https://github.com/LMCache/LMCache](https://link.zhihu.com/?target=https%3A//github.com/LMCache/LMCache)
|
||||
[Deploying DeepSeek with PD Disaggregation and Large-scale Expert Parallelism on 96 H100 GPUs](https://link.zhihu.com/?target=https%3A//lmsys.org/blog/2025-05-05-large-scale-ep/%23prefill-and-decode-disaggregation)
|
||||
[https://github.com/sgl-project/sglang/issues/4655](https://link.zhihu.com/?target=https%3A//github.com/sgl-project/sglang/issues/4655)
|
||||
[https://docs.sglang.ai/backend/pd_disaggregation.html](https://link.zhihu.com/?target=https%3A//docs.sglang.ai/backend/pd_disaggregation.html)
|
||||
[Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving](https://link.zhihu.com/?target=https%3A//arxiv.org/abs/2407.00079)
|
||||
[https://github.com/kvcache-ai/Mooncake](https://link.zhihu.com/?target=https%3A//github.com/kvcache-ai/Mooncake)
|
||||
[Mooncake 最新进展:SGLang 和 LMCache 基于 Mooncake 实现高效 PD 分离框架](https://zhuanlan.zhihu.com/p/1906034699358437813)
|
||||
[Mooncake (1): 在月之暗面做月饼,Kimi 以 KVCache 为中心的分离式推理架构](https://zhuanlan.zhihu.com/p/705754254)
|
||||
[Mooncake阅读笔记:深入学习以Cache为中心的调度思想,谱写LLM服务降本增效新篇章](https://zhuanlan.zhihu.com/p/706097807)
|
||||
[从MoonCake看大模型推理的PD分离,太快会扯到蛋吗?](https://zhuanlan.zhihu.com/p/8056351077)
|
||||
[https://github.com/ai-dynamo/dynamo](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/dynamo)
|
||||
[https://github.com/ai-dynamo/nixl](https://link.zhihu.com/?target=https%3A//github.com/ai-dynamo/nixl)
|
||||
[怎么看英伟达GTC新发布的推理框架Dynamo](https://zhuanlan.zhihu.com/p/31583638702)
|
||||
[Nvidia Dynamo 详解一](https://link.zhihu.com/?target=https%3A//ata.atatech.org/articles/11020396057%3Fspm%3Data.21736010.0.0.675927713lFoan)
|
||||
[https://github.com/NVIDIA/gdrcopy](https://link.zhihu.com/?target=https%3A//github.com/NVIDIA/gdrcopy)
|
||||
[sglang Dense LLM PD分离部署](https://link.zhihu.com/?target=https%3A//blog.csdn.net/u013701860/article/details/147745303)
|
||||
[NVIDIA Dynamo的PD分离有问题?我们提出的大模型推理系统"肾上腺素",是良药!](https://zhuanlan.zhihu.com/p/1888519961636487325)
|
||||
@@ -0,0 +1,81 @@
|
||||
# 📊 文章摘要:LLM关于PD分离的最新实测
|
||||
|
||||
> **原文**:[2025-06-22_LLM关于PD分离的最新实测.md](./2025-06-22_LLM关于PD分离的最新实测.md)
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/1919794916504114120
|
||||
> **来源**:知乎
|
||||
> **作者**:akaihaoshuai
|
||||
> **发布日期**:2025-06-22
|
||||
> **摘要日期**:2026-08-06
|
||||
> **价值评级**:⭐⭐⭐ 高
|
||||
|
||||
---
|
||||
|
||||
## 核心命题
|
||||
|
||||
> **实测边界** — 给出 PD 分离生效的量化阈值与工程落地经验,并指出其核心是 cache 调度。
|
||||
|
||||
---
|
||||
|
||||
## 文章概要
|
||||
|
||||
作者基于 vLLM/sglang 的 PD 分离实测,给出 9 条工程结论:PD 分离仅在超长上下文+大模型+高并发下收益明显(至少输入>8k、输出>100、并发>10、模型>32B),吞吐提升 20%~50%,且优化的是 TBT 而非 TTFT;P/D 配比 3P1D 较优、1P2D 更佳;prefill 可用 4090 这类"算力够、带宽差"的卡做异构部署。文章还逐一代码剖析了 SharedStorageConnector、P2pNcclConnector、LMCacheConnector、NixlConnector 与 sglang 的 PD 分离实现,并给出可直接复用的启动脚本。价值在于把 PD 分离从概念落实到"选型边界",并明确指出普通场景没必要折腾。
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **收益有明确阈值** — 至少输入>8k、输出>100、并发>10、模型>32B 左右才有效果;超长上下文+大并发下 TBT 可保持稳定,吞吐提升 20%~50% `[分类: 共识]`
|
||||
2. **PD 分离优化 TBT 而非 TTFT** — 且 prefill 卡减少(如 TP2 变 1P1D)会导致大 bs、长输入时 TTFT 变长 `[分类: 共识]`
|
||||
3. **P/D 配比反直觉** — 2P2D 一般不太行、3P1D 差不多;因 prefill 只执行一次而 decode 要很多遍,1P2D 更能提升整体资源利用率 `[分类: 争议]`
|
||||
4. **核心在于 cache 调度** — request 调度不能只考虑负载均衡,还要考虑 cache 复用率、显存剩余空间等 `[分类: 共识]`
|
||||
5. **传输方式决定 TTFT 损耗** — GPU 传输(NCCL)最快、基本保持原 TTFT,CPU/disk 传输都会使 TTFT 变慢;NCCL 初始化即固定全部 GPU、不适合动态扩缩容,Mooncake 统一多种传输方式,Dynamo 重新封装 nixl 协议 `[分类: 共识]`
|
||||
6. **异构框架最大化性价比** — 4090 算力约为 A/H 系列 30%~50% 但带宽不足 10%,非常适合 prefill 阶段;高带宽 GPU 做 decoding `[分类: 共识]`
|
||||
7. **分离后的固有资源短板** — Prefill server 带宽利用率低、decoder server GPU 利用率低,是 PD 分离需要接受的代价 `[分类: 共识]`
|
||||
|
||||
---
|
||||
|
||||
## 批判性分析
|
||||
|
||||
### 假设前提
|
||||
|
||||
假设读者具备 vLLM/sglang 使用经验;测试环境为作者自有的 GPU 集群,结论依赖具体模型(Qwen 系列)与负载形态,阈值未必能直接外推到其他硬件组合。
|
||||
|
||||
### 论据与逻辑
|
||||
|
||||
结论来自一手实测与源码阅读,可信度高;但未披露完整测试环境与数据细节,"20%~50%"为区间估计,缺少逐项实验数据表,难以复现验证。
|
||||
|
||||
### 边界与局限
|
||||
|
||||
作者明确给出适用边界——"能单卡跑的没必要多卡,能单机承载的没必要多机";结论在短上下文、小模型、低并发场景不适用,且 PD 分离本身会引入 P/D 两侧资源利用率失衡的新问题。
|
||||
|
||||
---
|
||||
|
||||
## 可引用金句
|
||||
|
||||
> "PD分离的核心其实在于cache的调度。"
|
||||
|
||||
> "能单卡跑的没必要多卡,能单机承载的没必要多机。"
|
||||
|
||||
---
|
||||
|
||||
## 总体评价
|
||||
|
||||
**亮点**:
|
||||
- 9 条实测结论量化了收益边界,反直觉结论(1P2D 优于 2P2D)有工程指导价值
|
||||
- 四种 KVConnector 的代码级对比透彻,启动脚本可直接复用
|
||||
- 异构硬件(4090 做 prefill)观点对成本敏感团队极有参考价值
|
||||
|
||||
**不足**:
|
||||
- 测试环境与数据细节披露不足,结论难以严格复现
|
||||
- 对 sglang 与 Mooncake 的介绍偏向代码流程转述
|
||||
- Dynamo/nixl 章节与"实测"主题关联度略松散
|
||||
|
||||
**适用场景**:推理服务工程师做 PD 分离技术选型与落地;需要判断"我的场景该不该上 PD 分离"的团队;预算有限、考虑异构卡部署的团队。
|
||||
|
||||
**关联建议**:结合极客博哥《LLM PD 分离背后的架构问题》对照架构决策维度;阅读 Mooncake 论文与 vLLM disaggregated serving 官方文档;跟踪 Dynamo 框架演进。
|
||||
|
||||
---
|
||||
|
||||
## 配图
|
||||
|
||||

|
||||
@@ -0,0 +1,83 @@
|
||||
# LLM PD 分离背后的架构问题
|
||||
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:极客博哥(solrex)
|
||||
> **发布日期**:2026-08-05
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/27836625742
|
||||
|
||||
---
|
||||
|
||||
PD 分离(Prefilling Decoding Disaggregation)推理是指将大模型推理的预填充阶段(P)和解码(D)阶段分离,以减少预填充与解码相互之间的影响,以便对两个阶段分别进行优化,提升 GPU 硬件的利用率,并减少推理延迟的一种推理技术方案。
|
||||
|
||||
在 DistServe、Mooncake 等论文中介绍分离式架构之后,DeepSeek V3 的报告让大家更进一步意识到 PD 分离可能是影响成本和性能的关键技术。
|
||||
|
||||
vLLM 对 PD 分离已经有了一个 1P1D 的实验版本。除此之外的开源框架大多还都不支持,不过很多已经在计划、实现中了。但纵览这些实现、文章或者计划,可以看到 PD 分离的架构选型上有很多问题需要思考,我尝试列举一下:
|
||||
|
||||
## 一、PD 是否直连传输?或是否需要 KV Cache Store/Pool?
|
||||
|
||||
PD 直连就是预填充节点直接将 KV Cache 发送给解码节点,它的好处是延迟低。但也意味着在整个 batch 的计算过程中锁定了P、D 节点的对应关系,一旦解码节点出现了问题,比如压力过大、服务出错、传输阻塞,在重试时无法仅调度 D 节点,需要重新进行整个预填充、解码过程。在 prompt 较长时,或者在 PD 节点数不对等的场景下,例如 2 个 P 对应到 1 个 D,重调度意味着抛弃较长或者多个 prefill batch,重调度的沉没成本较高。
|
||||
|
||||
使用 KV Cache Store/Pool 是在 P 和 D 之间增加了一个中间存储,预填充节点先将 KV Cache 写到中间存储,解码节点从中间存储读。这样做数据会多传输一次,增加了延迟,也增加了一些复杂度。但好处是容错性更好,还有就是预填充阶段本身也可以利用这个中间存储做 Prefix Caching。
|
||||
|
||||
中间存储也会对其它一些架构变动的复杂度产生影响,参见下面问题 四 和 五。
|
||||
|
||||
目前来看,Kimi Mooncacke、vLLM 的下一步设计、阿里 RTP-LLM 都使用或者计划使用基于 KV Cache Store/Pool 的方案,DeepSeek V3 报告中没有提到这部分。
|
||||
|
||||
在一些计算配比均衡、故障风险较小的场景下,比如同机多卡之间的 PD 分离,PD 直连的方案也有其简单易部署的优势。
|
||||
|
||||
## 二、P/D 是否按层发送/接收 KV Cache?
|
||||
|
||||
预填充最简单的实现是预填充节点完成第一个 token 的生成后,将所有的 KV Cache 传输给解码节点,这也是 vLLM 当前的实现。但这样实现有个问题,因为 KV Cache 的规模有可能非常大(尤其是原始 MHA),一个 batch 的 KV Cache 可能会是 GB 级别,都放在计算完成后传输,传输的延迟开销会比较大。
|
||||
|
||||
Kimi Mooncacke 和阿里 RTP-LLM 都采取了按层传输的方案,这是利用了 LLM 多层计算的自然特性。在完成一层的计算以后,就将这一层的 KV Cache 发送出去。这样 KV Cache 的发送就呈流式,既能降低延迟,也能使数据的发送更平滑。还存在一个更显著的优势,是 KV Cache 占用显存的时间更短,在显存紧张的情况下显存效率更高。
|
||||
|
||||
但按层发送对推理引擎的修改显然更大。我还没有看到开源的实现,猜测按层发送的引入对推理引擎的优化应该会有一定的影响,这里可能还需要一些精巧的设计才能减少影响。另外,按层发送对于 PD 非直连的场景下,中间存储的实现也会显著更复杂,QPS * num_hidden_layers,考虑到连续性可能还需要存储预分配和 session 保持。
|
||||
|
||||
因此对于 MLA 这种 KV Cache 偏小的注意力实现,比如 DeepSeek V3 的 KV Cache 是 576B/token/layer,是否要做按层发送,也许要看一下实际收益。
|
||||
|
||||
解码阶段和预填充阶段有所不同。解码需要多次迭代,在第一次迭代实现按层解码也没太大意义,而且涉及到计算的编排,应该需要拿到所有层的 KV Cache 才会开始计算。而且解码的计算时间比较长,如果解码的计算能够掩盖接收的延迟,不一定非要实现按层接收。
|
||||
|
||||
解码时按层接收,对调度也有一定挑战。从时序上来说,先发请求给预填充,完成后再发请求给解码会更自然。同时请求预填充和解码,需要处理一些同步问题,比如预填充压力大、解码等 KV Cache 超时等等。比如像阿里 RTP-LLM,它会观测预填充的排队情况,当一个请求进入预填充执行阶段时,解码端开始启动显存申请。
|
||||
|
||||
## 三、First Token 怎么处理
|
||||
|
||||
通常来说,预填充的同时会顺便把第一个 Token 计算出来,但计算到 hidden states 还是 token id 需要做一个选择。
|
||||
|
||||
计算到 hidden states 的好处是,预填充节点完全不需要加载和计算 lm_head 参数。比如 DeepSeek V3 的 lm_head 参数量是 0.9B,如果计算到 hidden states,这部分参数就完全不需要加载了。vLLM 目前就是采取的这个方式,预填充除了需要发送 KV Cache 之外,还需要发送一个 hidden states,解码时引擎也需要能支持加载 hidden states 延续计算。
|
||||
|
||||
计算到 token id 的好处是,发送的数据量小。以 DeepSeek V3 为例,hidden states 7K,token id 4B,完全可以跟着控制面消息传输。解码时引擎处理也更简单,因为 token id 到 token 的 detokenizer 一般是 CPU 查表,不涉及 tensor 的特殊处理。阿里 RTP-LLM 看起来采用的是这个方案。
|
||||
|
||||
## 四、Prefiller 和 Decoder 是否能相互转换?
|
||||
|
||||
当到达请求的 prompt 长度有差异性的时候,预填充和解码就会出现压力的不均衡问题。因为整体的吞吐取决于 P 和 D 的全局资源利用,当 P 过载但 D 闲置,或者 P 闲置但 D 过载的时候,成本和性能都不是最优的。
|
||||
|
||||
所以就需要考虑在 P 和 D 之间做负载均衡,要么从整个节点层面直接切换 P 和 D 的角色,要么 P 和 D 节点能够承担一些混杂的请求,比如通过 chunked prefill。
|
||||
|
||||
这时候 P 和 D 是否直连对实现复杂度就有一些影响了,如果有中间存储的存在,通过 PD 转换做负载均衡的实现难度会降低很多。
|
||||
|
||||
## 五、Decoder 能填充 KV Cache 吗?
|
||||
|
||||
如果业务应用场景中会将生成的 context 也作为下一轮的输入,还可能需要考虑 Decoder 填充 KV Cache,用于下一轮的 prefix caching 复用。这时候,KV Cache Store/Pool 的存在,对流畅交互有比较大的意义。
|
||||
|
||||
## 六、KV Cache Store/Pool 的设计抉择
|
||||
|
||||
有别于我们通常的 KV 存储,由于 GPU、RDMA(IB、RoCE)、NVLink 新硬件的存在,KV Cache Store/Pool 的设计抉择点会非常多。
|
||||
|
||||
在存储上,有 VRAM、DRAM、NVMe SSD,要选择 KV Cache Store 使用哪些介质。虽然对于 MHA 来说,因为 KV Cache 太大,基于 SSD 存储并不现实,但是对于 MQA、MLA 来说,NVMe SSD 并不是不可用。
|
||||
|
||||
在通信上,有 TCP、NVLink、RDMA、GPU Direct RDMA、NVMe over RDMA。为了更高的性能,KV Cache Store 在数据面上可能要考虑使用更快、更直接的传输方法。但 RDMA 对数据访问的抽象比 TCP 复杂很多,TCP 就是一端发一端收,但 RDMA 很多是单边操作。比如数据从 A 机 VRAM 发送到 B 机 DRAM,可能有以下方法:
|
||||
|
||||
- A 从 VRAM 复制到 DRAM 再写 B 的 DRAM
|
||||
- A 从 VRAM 复制到 DRAM 再让 B 读 A 的 DRAM
|
||||
- A 直接从 VRAM 复制到 B 的 DRAM
|
||||
- B 直接读 A 的 VRAM
|
||||
|
||||
如果再加上 NVMe over RDMA,那要考虑的东西就更多了。P 发送到 Store,D 从 Store 接收,到底要通过哪些模式支持,是需要思考的。目前来看,预填充节点更适合单边写到 Store,这样能减少状态传输,更快地释放显存,但如果预填充节点也要读 prefix cache,那情况可能反过来;解码节点可能更适合单边读 Store。
|
||||
|
||||
在分布式架构上,无论是做集群式的 KV Cache Store,还是单机 side-car 式的 KV Cache Store,都需要存储一些 meta,并且在 P、D 之间传输一些控制信息。学术界有一些完全基于 RDMA 实现的分布式 KV 数据库,但目前看复杂度还是比较高,也没有开源的实现。目前业界实现还是倾向于使用传统的 RPC 方式来传输控制信息,并且通过分布式技术方案做 meta 节点的一致性、可靠性设计。
|
||||
|
||||
在接口 API 上,KV Cache Store 比传统的 KV Store 要复杂一些。比如要支持写的时候分 layer 写,读的时候能读到连续的内容;还可能要支持队列式的读,写完的 layer 可以很快被读走。如果要支持 prefix caching,还存在 KV Cache 的链式关系,写的时候不仅要分 layer,还要分 page,读的时候也是。TP/SP 等并行计算机制,对 API 可能还会有一些额外的要求。
|
||||
|
||||
在数据结构上,如果希望从 VRAM 直接写 Store,减少一次复制,引擎本身的 KV Cache 数据结构就需要与 Store 的数据结构进行一定程度的对齐;如果希望同时兼做 prefix caching,那 store 的数据排布就要考虑相同 prefix 的 page 更接近,甚至共享。比如用 prompt 的所有 page 的 hash 组成 string,按前缀 range 分桶,桶内对相同前缀做 merge/引用等等,这在存储优化上会是一个挑战。
|
||||
|
||||
整体来看,PD 分离的实现上有很多架构问题需要抉择,目前还没有一个理想的架构方案,或许未来也会是根据不同场景有很多参数化的灵活配置。
|
||||
@@ -0,0 +1,78 @@
|
||||
# 📊 文章摘要:LLM PD 分离背后的架构问题
|
||||
|
||||
> **原文**:[2026-08-05_LLM_PD_分离背后的架构问题.md](./2026-08-05_LLM_PD_分离背后的架构问题.md)
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/27836625742
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:极客博哥(solrex)
|
||||
> **发布日期**:2026-08-05
|
||||
> **摘要日期**:2026-08-06
|
||||
> **价值评级**:⭐⭐⭐ 高
|
||||
|
||||
---
|
||||
|
||||
## 核心命题
|
||||
|
||||
> **架构抉择** — PD 分离落地前必须系统回答的六大架构决策问题,作者以工程视角指出目前尚无理想方案。
|
||||
|
||||
---
|
||||
|
||||
## 文章概要
|
||||
|
||||
本文系统梳理 PD 分离实现层面的架构选型问题,包括 PD 直连与 KV Cache Store/Pool 之争、KV Cache 是否按层传输、首 token 的 hidden states/token id 处理、Prefiller 与 Decoder 角色互换、Decoder 回填 KV Cache,以及 KV Cache Store 在存储介质、通信协议、分布式架构与数据结构上的设计抉择。其价值在于:主流资料多讲 PD 分离的收益,本文聚焦实现前的决策空间,并对照 vLLM、Mooncake、阿里 RTP-LLM 等现有实现的选择。局限是观点多为工程观察与推测,缺乏实验数据支撑。
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **PD 直连 vs KV Cache Store/Pool 是首要抉择** — 直连延迟低但锁定 P/D 节点对应关系、重调度沉没成本高;中间存储多一次传输但容错更好、可兼做 Prefix Caching。Mooncake、vLLM 下一步设计、RTP-LLM 均选后者 `[分类: 共识]`
|
||||
2. **按层传输是流式化趋势但代价高昂** — Mooncake、RTP-LLM 按层发送 KV Cache 以降低延迟与显存占用时长,但推理引擎改造大、中间存储实现显著复杂(需处理 QPS × 层数的存储预分配与 session 保持);对 MLA 这类 KV Cache 偏小的注意力实现是否值得需看实际收益 `[分类: 争议]`
|
||||
3. **首 token 的两种计算路径** — 算到 hidden states 免加载 lm_head(DeepSeek V3 为 0.9B 参数,vLLM 采用);算到 token id 传输量小、解码端处理简单(RTP-LLM 采用)`[分类: 争议]`
|
||||
4. **P/D 角色可转换是负载均衡的前提** — prompt 长度差异导致 P/D 压力失衡,需节点级角色切换或 chunked prefill 兜底;存在中间存储时转换实现难度大幅降低 `[分类: 未探索]`
|
||||
5. **KV Cache Store 的设计抉择远超传统 KV 存储** — 涉及 VRAM/DRAM/NVMe SSD 介质选择(MQA/MLA 下 SSD 并非不可用)、TCP/NVLink/RDMA/GPU Direct RDMA 单边操作、RPC 控制面与 meta 一致性、分 layer/page 写入及链式 prefix 引用等挑战,目前无开源完整方案 `[分类: 未探索]`
|
||||
6. **解码端按层接收对调度构成挑战** — 同时请求 P/D 需处理预填充排队观测、解码端显存预申请等同步问题(如 RTP-LLM 在请求进入 prefill 执行阶段时启动解码端显存申请)`[分类: 未探索]`
|
||||
|
||||
---
|
||||
|
||||
## 批判性分析
|
||||
|
||||
### 假设前提
|
||||
|
||||
假设 PD 分离是值得投入的技术方向(以 DistServe、Mooncake、DeepSeek V3 报告为背景);假设读者熟悉 vLLM、Mooncake、RTP-LLM 等实现细节。若场景是单卡、短上下文或小规模部署,文中多数决策问题不成立。
|
||||
|
||||
### 论据与逻辑
|
||||
|
||||
以工程观察和开源实现对照支撑论点,逻辑链条完整;但"按层发送对推理引擎的优化应该会有一定的影响"等表述作者自承是"猜测",缺少量化验证;MLA 场景是否值得按层传输也只停留在"要看实际收益"的开放判断。
|
||||
|
||||
### 边界与局限
|
||||
|
||||
作者明确承认"目前还没有一个理想的架构方案",并指出结论随场景而异(如同机多卡 PD 直连自有其简单易部署的优势);结论适用于长上下文、大并发、需多机部署的中大型推理服务,不适用于计算配比均衡、故障风险小的同机简单场景。
|
||||
|
||||
---
|
||||
|
||||
## 可引用金句
|
||||
|
||||
> "整体来看,PD 分离的实现上有很多架构问题需要抉择,目前还没有一个理想的架构方案,或许未来也会是根据不同场景有很多参数化的灵活配置。"
|
||||
|
||||
---
|
||||
|
||||
## 总体评价
|
||||
|
||||
**亮点**:
|
||||
- 系统化提出六大架构决策框架,是目前少见的"实现前决策清单"类文章
|
||||
- 每种方案均给出利弊与业界实现(Mooncake/vLLM/RTP-LLM/DeepSeek V3)对照
|
||||
- 边界意识强,明确区分适用与不适用场景
|
||||
|
||||
**不足**:
|
||||
- 无实验数据,多处判断停留在推测层面
|
||||
- 按层发送对 MLA 的收益评估未深入展开
|
||||
- KV Cache Store 控制面方案(RPC vs RDMA)讨论点到为止
|
||||
|
||||
**适用场景**:推理系统架构师、GPU 集群服务化团队在 PD 分离技术选型前的决策参考;理解 Mooncake、vLLM、RTP-LLM 设计取舍时的对照材料。
|
||||
|
||||
**关联建议**:结合 DistServe 论文(动机与 SLO 建模)、Mooncake 论文(KVCache 中心调度)阅读;与 akaihaoshuai《LLM关于PD分离的最新实测》互补——前者给决策维度,后者给实测边界。
|
||||
|
||||
---
|
||||
|
||||
## 配图
|
||||
|
||||

|
||||
@@ -0,0 +1,362 @@
|
||||
# 大模型系列:深度解析 Prefill-Decode 分离式部署架构
|
||||
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:猫先生
|
||||
> **发布日期**:2025-06-17
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/1918334902492963669
|
||||
|
||||
---
|
||||
|
||||
〔更多精彩AI内容,尽在「魔方AI空间」,引领AIGC科技时代〕
|
||||
|
||||
> 本文作者:猫先生
|
||||
> 【从零走向AGI】旨在深入了解通用人工智能(AGI)的发展路径,从最基础的概念起,逐步构建完整的知识体系。
|
||||
> 项目地址 :
|
||||
|
||||
---
|
||||
|
||||
在上一篇文章中,我们介绍了NVIDIA 发布的Dynamo框架及其PD分离式部署技术,旨在优化大语言模型(LLM)推理过程中的资源利用和推理效率。
|
||||
|
||||
《大模型系列:NVIDIA Dynamo框架详解——PD分离式部署技术解析》
|
||||
|
||||
Dynamo的PD分离式部署技术通过优化资源分配和推理流程,显著提升了LLM推理的效率和资源利用率,有望成为未来AI推理服务的重要架构。
|
||||
|
||||
那么,本文将深度解析 Prefill-Decode 分离式部署架构的原理!!
|
||||
|
||||
我们开始吧!!
|
||||
|
||||
## 一、什么是Prefill-Decode分离架构
|
||||
|
||||
**预填充-解码阶段分离**是一种用于处理长上下文大型语言模型(LLMs)的方法,旨在通过将推理过程分为两个主要阶段——**预填充(Prefill)和解码(Decoding)**,这两个阶段被拆分到不同的 GPU 实例上独立运行。如下图所示,DistServe论文中的架构图。
|
||||
|
||||
### 预填充阶段(Prefill Phase)
|
||||
|
||||
- **目标**:预填充阶段的主要目标是处理输入序列的所有输入token,以构建键值缓存(KV Cache)。这个缓存用于存储中间计算结果,以便在后续的解码阶段重用。
|
||||
- **特点**:预填充阶段通常是**计算密集型的**,因为它需要处理整个输入序列,并生成初始的输出标记。由于注意力机制的计算复杂度与**输入序列长度的平方**成正比,因此**长序列的处理需要更多的计算资源。**
|
||||
|
||||
### 解码阶段(Decoding Phase)
|
||||
|
||||
- **目标**:解码阶段的任务是**基于预填充阶段构建的键值缓存**,逐个生成输出token。由于每个新生成的token只需要计算与之相关的键值缓存,因此解码阶段的计算负载相对较轻。
|
||||
- **特点**:**解码阶段通常需要较少的计算资源**,但仍然需要**频繁访问键值缓存**。为了减少干扰,PDD将解码阶段与预填充阶段**分离到不同的GPU组。**
|
||||
|
||||
## 二、为什么LLM推理分成两个阶段:Prefill 和 Decode?
|
||||
|
||||
要想回答这个**"为什么"**,我们需要首先搞懂 **prefill 阶段的内部机制,attention 的计算细节、KV Cache 是如何初始化的、为什么 prefill 计算量这么大。**
|
||||
|
||||
**在传统集成式推理流水线中**,LLM的Prefill和Decode阶段往往被置于同一GPU上运行,导致资源需求不匹配,资源利用率不高。例如,当用户请求的Prefill长度和Decode长度非常不匹配时,同一GPU需要同时处理高算力需求和高内存带宽需求的任务,难以发挥最佳性能。
|
||||
|
||||
**一句话简单理解**:LLM生成文本的过程本质上是**给定上下文,逐词预测下一个词**。但在实现上,这个过程被明确地**分成两个阶段:**
|
||||
|
||||
| 阶段 | 资源需求特性 | 计算模式 | 显存占用模式 | 目的 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Prefill | 计算密集型 | 高并行度,矩阵乘法为主 | 低,固定规模 | 模型读取并"理解"你输入的所有上下文 |
|
||||
| Decode | 内存密集型 | 顺序生成,访存为主 | 随上下文增长指数级上升 | 模型基于已有信息逐步生成回复 |
|
||||
|
||||
Prefill 是用户输入完 prompt 到生成首个 token 的过程,Decode 则为生成首个 token 到推理停止的过程。
|
||||
|
||||
那么,这样我们就很好理解,
|
||||
|
||||
**为什么不能一个阶段,而必须拆分成两个阶段进行:**
|
||||
|
||||
- 输入 prompt 是完整的、一次性提供的,**适合并行计算。**
|
||||
- 输出 token 是未知的,只能**一个一个推理,必须串行。**
|
||||
|
||||
**在Prefill阶段**,大模型一次性对prompt中所有token进行计算QKV,由于不同token的计算是独立的,因此该过程可以并行。**在Attention部分**,计算得到的QKV进一步计算出Output矩阵,再经过后续的FFN层和解码**得到首字母token。**
|
||||
|
||||
**在Decode阶段**,计算原理和 Prefill 完全相同,但计算方式却不能一样。**原因有两个:**
|
||||
|
||||
**第一:随着序列长度的增加**,Attention 计算复杂度平方级增长,直接计算代价很大,导致长序列的推理时间极慢,甚至不可行。
|
||||
|
||||
**第二:对Decode阶段**的计算过程简单分析发现,该过程可以复用 Prefill 阶段的KV结果,也可以复用Decode阶段已经产生的KV结果。
|
||||
|
||||
**综上,可以把已产生的KV存起来**,不必重新计算,这就是KV Cache。对于Q矩阵,每次需要计算的只是Q的最后一行q,计算关于**qKV的attention**,而不是关于**QKV的attention**,这样**复杂度降低了一个量级,实现以存换算。**
|
||||
|
||||
## 三、Prefill 内部运行机制
|
||||
|
||||
> **Prefill 阶段是语言模型推理中的第一个步骤**,它负责处理你输入的所有上下文内容(prompt),为后续生成打下基础。
|
||||
|
||||
比如你问模型一句话:
|
||||
|
||||
"请解释一下 Transformer 的原理。"
|
||||
|
||||
这句话会被 tokenizer 编码为一串 token,比如 `["请", "解释", "一下", "Trans", "##former", "的", "原理", "。"]`。
|
||||
|
||||
然后这些 token 会进入 Transformer 模型进行前向传播。想要更详细了解Transformer的运行原理,可以参考这篇文章《新手必看 | 44张图带您极简学习Transformer | 分步数学示例(建议收藏)》
|
||||
|
||||
**重点来了**
|
||||
|
||||
**Prefill 中模型内部到底发生了什么?**
|
||||
|
||||
**Step 1:Embedding 输入**
|
||||
|
||||
- 每个 token 会映射成一个向量(embedding),形状为 `[batch_size, seq_len, hidden_dim]`
|
||||
|
||||
**Step 2:Self-Attention 的全量计算**
|
||||
|
||||
- 输入是完整的上下文,因此模型会执行一次完整的 masked self-attention。对于位置 i 的 token,会计算它和前面所有位置的注意力(包括自己):
|
||||
|
||||
**Step 3:生成 KV Cache**
|
||||
|
||||
- 每层 Transformer 都会把每个 token 的 K 和 V 存下来,形成 KV Cache:
|
||||
|
||||
```
|
||||
KV Cache = [K₁, K₂, ..., Kₙ], [V₁, V₂, ..., Vₙ]
|
||||
```
|
||||
|
||||
这个 Cache 会在 decode 阶段被反复使用,避免重复计算。
|
||||
|
||||
## 四、为什么 prefill 的计算成本那么高?
|
||||
|
||||
让我们做个简单对比:
|
||||
|
||||
| | Prefill | Decode(单步) |
|
||||
| --- | --- | --- |
|
||||
| 处理 token 数 | 全部 prompt(如几百) | 1 个 |
|
||||
| Attention 计算 | 全 attention matrix | 只看已有 KV |
|
||||
| 是否可并行 | ✅ 是 | ❌ 否(必须串行) |
|
||||
| 计算资源 | 重 | 轻 |
|
||||
|
||||
> Prefill 最大的特点是:
|
||||
|
||||
- 需要 **"每个 token 与前面所有 token 做 attention"**
|
||||
- 不能复用 KV Cache(因为是第一次建立)
|
||||
|
||||
**Prefill 是典型的 compute-bound 阶段**:
|
||||
|
||||
- 大量矩阵乘法和 attention 计算主导性能瓶颈
|
||||
- GPU 的算力利用率很高,但内存带宽压力较小
|
||||
|
||||
因此如果你的 prompt 很长,Prefill 阶段就会非常耗时。很多模型响应慢,不是生成慢,而是 prompt 处理慢。
|
||||
|
||||
## 五、Decode:token-by-token 地生成输出
|
||||
|
||||
在 prefill 之后,模型已经建立了一个完整的 KV Cache,可以开始逐步生成 token。
|
||||
|
||||
每次 decode 只需要:
|
||||
|
||||
- 把最新生成的 token 输入进去
|
||||
- 拿之前的 KV Cache 来做 attention
|
||||
- 预测下一个 token
|
||||
|
||||
**Decode 是典型的 memory-bound 阶段**:
|
||||
|
||||
- 每生成一个 token,都需要访问所有历史的 KV Cache(多层、多头)
|
||||
- 计算量小,但内存带宽压力大。
|
||||
- 特别在 batch size 小、生成序列长的场景,GPU 利用率会很低。
|
||||
|
||||
## 六、Prefill vs Decode 的性能瓶颈差异
|
||||
|
||||
由于Prefill、Decode这两个阶段的输入特性和计算方式**本质不同,**所以将其拆分成两个阶段是**为了精准优化每一步的计算路径**,比如:
|
||||
|
||||
- Prefill 可用 FlashAttention 等并行技术提升性能
|
||||
- Decode 可用 KV Cache、speculative decoding 等加速生成
|
||||
|
||||
在推理过程中,**Prefill 和 Decode 阶段不仅在结构上不同,在性能瓶颈上也大相径庭**:
|
||||
|
||||
| 阶段 | 特点 | 性能瓶颈 | 原因 |
|
||||
| --- | --- | --- | --- |
|
||||
| Prefill | 一次处理整个输入序列 | Compute-bound | 多 token 并行计算,Attention + MLP 计算密集 |
|
||||
| Decode | 每次生成一个 token,逐步执行 | Bandwidth-bound | 每次要读取大量 KV Cache,但计算量小,等数据成为瓶颈 |
|
||||
|
||||
### 为什么 Decode 会是 Bandwidth-bound?
|
||||
|
||||
在 Decode 阶段,虽然只生成一个新 token,但为了计算它的注意力得分,需要加载 **全部历史 token 的** **KV** **Cache**。这意味着:
|
||||
|
||||
- 每层都要从 GPU 内存中读取大量数据;
|
||||
- 实际计算(比如 Q × K^T)规模却很小;
|
||||
- 导致 GPU 大量时间都在等内存传输,**而不是在计算**。
|
||||
|
||||
这就是典型的 **Bandwidth-bound** 场景 —— **内存带宽**成为限制性能的关键因素,而不是算力本身。
|
||||
|
||||
| 类型 | 具体含义 | 常见表现 |
|
||||
| --- | --- | --- |
|
||||
| Compute-bound | 受限于计算单元(ALU、CUDA 核心等) | GPU 计算占满 |
|
||||
| Bandwidth-bound | 受限于 访问速度:内存太慢,等数据成为瓶颈 | GPU 闲着在等内存 |
|
||||
| Memory-bound | 受限于 内存容量,模型或缓存太大放不下 | OOM / 频繁调度数据 |
|
||||
|
||||
## 七、PD分离原理
|
||||
|
||||
通过以上内容的分析,我们就能够很容易的理解PD分离式部署的原理了。**简单来说**,将Prefill(预填充)和Decode(解码)这两个推理阶段分开处理的技术,通常适用于对时延有严格要求的场景。
|
||||
|
||||
**将Prefill实例和Decode实例分开部署**,减少Prefill阶段和Decode阶段分时复用在时延上造成的互相干扰,实现同等时延下,提升吞吐量。
|
||||
|
||||
**PD分离工作原理如下图所示。**
|
||||
|
||||
**PD分离部署的优势:**
|
||||
|
||||
- **资源利用优化**:由于Prefill阶段计算密集,而Decode阶段计算较为稀疏,将这**两个阶段分离可以更好的利用GPU的计算资源。**
|
||||
- **提高吞吐量**:分离后的Prefill和Decode可以同时处理不同的请求,这意味着在Prefill阶段处理新请求的同时,Decode阶段可以继续**处理之前请求的解码任务**,从而提高了整体的处理能力。
|
||||
- **降低延迟**:由于Prefill和Decode分别在不同的阶段进行,**可以减少等待时间**,特别是当有多个请求并发到达时。
|
||||
|
||||
## 八、PD分离通信协议
|
||||
|
||||
在大模型推理中:
|
||||
|
||||
- **Prefill 阶段**:一次性处理输入 prompt(比如几千个 token),计算代价大、计算密集、通信密集;
|
||||
- **Decode 阶段**:逐 token 生成输出,计算相对轻量,但延迟敏感。
|
||||
|
||||
**PD 分离** 的思路是:
|
||||
**让 prefill 与 decode 阶段分别运行在不同的 worker 上(甚至不同节点上),形成更灵活的资源编排。**
|
||||
|
||||
这样可以让大模型推理 pipeline 化,提高吞吐量(Throughput)和利用率。
|
||||
|
||||
但 PD 分离带来的挑战是:prefill 输出的 **KV Cache(注意力缓存)** 要传递给 decode worker,这就需要高效的 **跨设备通信协议**。
|
||||
|
||||
### 1、NCCL
|
||||
|
||||
**NCCL (NVIDIA Collective Communication Library)** 是 NVIDIA 官方推出的 **GPU 间高性能通信库**,广泛用于分布式训练和推理。
|
||||
|
||||
它为深度学习框架(如 PyTorch、Megatron、vLLM、DeepSpeed 等)提供高效的 **collective communication primitives**:AllReduce、AllGather、ReduceScatter、Broadcast、Send/Recv。
|
||||
|
||||
| 特性 | 说明 |
|
||||
| --- | --- |
|
||||
| 底层协议 | 基于 NVLink / NVSwitch / PCIe / InfiniBand / RoCE |
|
||||
| 通信模式 | 点对点(P2P)与集合通信(collective)均支持 |
|
||||
| 典型用途 | 模型并行(Tensor/Sequence Parallel)、梯度同步、KV Cache 共享 |
|
||||
| 性能特征 | 延迟低、带宽高,尤其适合单机多卡或同集群高带宽环境 |
|
||||
| 限制 | 主要用于 GPU–GPU 间通信,不适合 CPU 或异构网络场景 |
|
||||
|
||||
在 PD 分离架构中,**如果 prefill worker 与 decode worker 处于同一 GPU 集群中(如同机或同网段 NVLink 环境)**,
|
||||
NCCL 是最常用的通信方式:
|
||||
|
||||
- Prefill 阶段完成后,将 KV Cache tensor 通过 NCCL 的 `Send/Recv` 或 `AllGather` 传给 Decode worker;
|
||||
- Decode worker 接收并继续推理。
|
||||
|
||||
**优点**:传输快、延迟低。
|
||||
**缺点**:只能在 GPU 直连或高速互联环境下使用(如 NVLink、IB/RoCE)。
|
||||
|
||||
### 2、NIXL
|
||||
|
||||
> **NIXL (NVIDIA Interconnect eXtension Layer)** 是 NVIDIA 新一代跨节点通信层,用于支持 **异构节点间的高效推理通信**,尤其是 **PD 分离架构下的远程 Prefill–Decode 数据传递**。
|
||||
|
||||
它是一个抽象通信层,位于 NCCL 和更高层推理框架(如 **Dynamo Inference Framework**, **TensorRT-LLM**, **vLLM**) 之间。
|
||||
|
||||
> 可以理解为:**NIXL = 面向推理系统的"远程 NCCL"**
|
||||
|
||||
| 特性 | 说明 |
|
||||
| --- | --- |
|
||||
| 定位 | NCCL 的扩展层,支持跨节点 / 跨网络传输 |
|
||||
| 通信语义 | 统一封装 Send/Recv、RDMA、ZeroCopy 等接口 |
|
||||
| 支持硬件 | 支持 NVLink、NVSwitch、InfiniBand、Ethernet |
|
||||
| 优化目标 | 降低跨节点 Prefill→Decode KV 传输延迟 |
|
||||
| 使用场景 | PD 分离架构、异构 GPU 集群、解耦式推理管线 |
|
||||
|
||||
- **NCCL**:适合 **单机或高带宽集群内** 的 GPU–GPU 通信;
|
||||
- **NIXL**:是 **NCCL 的远程扩展层**,用于 **跨节点 / 异构环境** 的高性能通信,特别针对 **Prefill–Decode 分离架构** 的 KV Cache 远程传输场景。
|
||||
|
||||
## 九、追溯PD分离技术
|
||||
|
||||
### (一)论文《SARATHI: Efficient LLM Inference by Piggybacking Decodes with Chunked Prefills[1]》
|
||||
|
||||
时间:2023.8
|
||||
|
||||
提出了SARATHI技术来解决**LLM推理效率低下**的问题。
|
||||
|
||||
**随着语言模型的规模不断扩大**,推理所需的GPU计算资源显著增加,尤其是在小批量情况下,解码阶段的计算利用率较低,导致整体推理效率低下。
|
||||
|
||||
**通过改进预填充(prefill)和解码(decode)阶段的调度策略来提高LLM推理的效率。**具体来说,SARATHI通过使用**分块预填充和最大解码批处理**来解决这些问题。
|
||||
|
||||
- **分块预填充(Chunked-prefills)**:
|
||||
|
||||
- 将一个预填充请求分割成多个等大小的块,以最大化GPU的计算利用率。
|
||||
- 通过分割预填充请求,可以在单个预填充请求中构建多个解码最大批次,从而提高解码的覆盖范围。
|
||||
|
||||
- **最大解码批处理(Decode-maximal batching)**:
|
||||
|
||||
- 使用单个预填充块构建一个批次,并用解码请求填充剩余的槽位。
|
||||
- 这种混合批处理提供了既计算饱和又均匀的工作单元,解决了低效解码和管道气泡的问题。
|
||||
|
||||
### (二)论文《DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving[2]》
|
||||
|
||||
时间:2024.1月
|
||||
|
||||
https://github.com/LLMServe/DistServe
|
||||
|
||||
提出DistServe,一种通过解耦预填充和解码计算来优化LLM服务性能的系统。
|
||||
|
||||
**现有系统将预填充和解码阶段合并处理**,导致强烈的预填充-解码干扰和资源分配与并行计划的耦合;不同应用对每个阶段的延迟要求不同,如实时聊天机器人强调低首次token时间(TTFT),而文档摘要则强调低每个输出token的耗时(TPOT)。
|
||||
|
||||
**相关工作**:该问题的研究相关工作有:**vLLM和DeepSpeed-MII**等系统采用了**批处理和模型并行**策略来提高整体系统吞吐量,但这些方法未能有效解决预填充和解码阶段的干扰问题。
|
||||
|
||||
**DistServe**将预填充和解码阶段的**计算分配到不同的GPU上**,从而**消除预填充-解码干扰**。预填充阶段处理用户提示以生成响应的第一个token,而解码阶段则逐步生成后续token。
|
||||
|
||||
### (三)论文《LoongServe: Efficiently Serving Long-Context Large Language Models with Elastic Sequence Parallelism[3]》
|
||||
|
||||
时间:2024.4月
|
||||
|
||||
https://github.com/LoongServe/LoongServe
|
||||
|
||||
提出LoongServe系统,通过**弹性序列并行性(ESP)**来高效地服务长上下文LLMs。
|
||||
|
||||
**大语言模型的上下文窗口迅速增加**,导致不同请求和同一请求的不同阶段之间的资源使用差异巨大。现有的静态并行策略无法有效利用底层资源来处理可变长度的请求。
|
||||
|
||||
弹性序列并行性(ESP),以适应不同请求和阶段的动态变化。基于ESP,设计了LoongServe系统,旨在提高计算效率、通信效率和GPU内存效率。
|
||||
|
||||
ESP动态调整每个迭代的并行度(Degree of Parallelism, DoP),**以适应不同请求和阶段的资源需求**。在预填充阶段,**ESP可以设置较高的DoP以快速处理请求**;**在解码阶段,ESP可以降低DoP以减少通信开销并释放资源。**
|
||||
|
||||
### (四)论文《Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving[4]》
|
||||
|
||||
时间:2024.6月
|
||||
|
||||
https://github.com/kvcache-ai/Mooncake
|
||||
|
||||
https://github.com/vllm-project/vllm/pull/10502
|
||||
|
||||
Mooncake,一种以KVCache为中心的分散化架构,用于大语言模型(LLM)的推理服务。
|
||||
|
||||
这篇文章要解决的问题是如何在LLM服务中,特别是处理长上下文和过载场景时,提高整体有效吞吐量并满足延迟相关的服务水平目标(SLOs)。
|
||||
|
||||
该问题的研究难点包括:如何在过载场景下预测未来的负载并提前拒绝某些请求以节省计算资源;如何有效地分离预填充和解码阶段以提高缓存利用率;如何在保证延迟要求的前提下最大化吞吐量。
|
||||
|
||||
该问题的研究相关工作有:Orca使用迭代级调度以实现各阶段的并发处理;vLLM利用动态KV缓存管理优化内存;FlexGen、SARATHI和FastServe结合创新的调度和交换策略以有效分配工作负载。此外,Splitwise提出了分离预填充和解码阶段的分解架构,DistServe优化了每阶段的资源分配和并行策略,TetraInfer结合了分块预填充和两级分解以及预测的两级调度算法。
|
||||
|
||||
### (五)论文《Speculative Prefill: Turbocharging TTFT with Lightweight and Training-Free Token Importance Estimation[5]》
|
||||
|
||||
时间:2025.2.5日
|
||||
|
||||
SPECPREFILL的框架,旨在通过**轻量级和无需训练**的标记重要性估计来加速大语言模型(LLM)的推理时间。
|
||||
|
||||
这篇文章的研究背景是提高时间到第一个标记(TTFT)在现代大型语言模型(LLM)推理引擎中至关重要。优化TTFT可以直接提高最大每秒查询数(QPS),满足许多关键应用的需求。然而,提升TTFT极具挑战性,因为它是计算受限的,并且性能瓶颈从自注意力转移到了多层感知机(MLP)部分。
|
||||
|
||||
预填充阶段主要是计算受限的,且瓶颈可能会随着提示长度和批量大小的变化而变化;直接优化TTFT会导致自注意力部分向MLP部分转移,从而增加计算复杂度。
|
||||
|
||||
### (六)论文《LServe: Efficient Long-sequence LLM Serving with Unified Sparse Attention[6]》
|
||||
|
||||
时间:2025.2.20日
|
||||
|
||||
LServe的系统,旨在通过混合稀疏注意力机制来高效地服务长序列大型语言模型(LLMs)。该系统通过统一块稀疏注意力框架来加速长序列LLM的预填充和解码阶段。
|
||||
|
||||
**背景:**
|
||||
|
||||
- 长序列LLMs在处理复杂任务时表现出色,但其在预填充和解码阶段的效率问题仍然存在。预填充阶段的注意力计算复杂度为二次,而解码阶段的内存占用较大。
|
||||
- 现有的加速方法主要集中在KV缓存的量化或静态稀疏注意力上,但这些方法在保持长上下文能力方面存在不足。
|
||||
|
||||
**LServe系统**:
|
||||
|
||||
- LServe通过引入混合稀疏注意力机制来解决这些问题。它将不同的硬件友好的结构化稀疏模式统一到一个框架中,通过在块级别跳过不重要的计算来加速注意力计算。
|
||||
- 在预填充阶段,LServe将一半的注意力头转换为几乎免费的流式头,并在解码阶段使用查询为中心的动态稀疏性来优化KV缓存。
|
||||
|
||||
实验表明,LServe在预填充阶段比现有的vLLM系统快2.9倍,在解码阶段平均快1.3到2.1倍,同时保持了长上下文的准确性。
|
||||
|
||||
## 十、vLLM中的PD分离架构
|
||||
|
||||
vLLM的PD分离架构主要由三个组件构成:Proxy API server、vLLM prefill和vLLM decode。以下是它们的工作原理:
|
||||
|
||||
1️⃣ 当请求到来时,首先会进入Proxy API server。Proxy API server会将请求转发给vLLM prefill。
|
||||
|
||||
2️⃣ vLLM prefill负责进行prefill操作,生成kv cache,并将这个缓存转发给vLLM decode。
|
||||
|
||||
3️⃣ Proxy API server继续将请求发送给vLLM decode。vLLM decode会执行drop_select操作,这个操作主要是获取kv和跳过prefill。完成drop_select后,vLLM decode会生成First token。
|
||||
|
||||
4️⃣ vLLM decode阶段也会生成First token。Proxy API server最终获取的所有token都是从vLLM decode获取的。vLLM prefill只负责生成kv cache。
|
||||
|
||||
通过这种方式,vLLM的PD分离架构能够实现高效的请求处理和缓存管理。
|
||||
|
||||
## 参考资料
|
||||
|
||||
> [1] SARATHI: Efficient LLM Inference by Piggybacking Decodes with Chunked Prefills: _https://arxiv.org/pdf/2308.16369v1.pdf_
|
||||
> [2] DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving: _https://arxiv.org/pdf/2401.09670v3.pdf_
|
||||
> [3] LoongServe: Efficiently Serving Long-Context Large Language Models with Elastic Sequence Parallelism: _https://arxiv.org/pdf/2404.09526v2.pdf_
|
||||
> [4] Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving: _https://arxiv.org/pdf/2407.00079v3.pdf_
|
||||
> [5] Speculative Prefill: Turbocharging TTFT with Lightweight and Training-Free Token Importance Estimation: _https://arxiv.org/pdf/2502.02789v2.pdf_
|
||||
> [6] LServe: Efficient Long-sequence LLM Serving with Unified Sparse Attention: _https://arxiv.org/pdf/2502.14866v2.pdf_
|
||||
@@ -0,0 +1,80 @@
|
||||
# 📊 文章摘要:大模型系列:深度解析 Prefill-Decode 分离式部署架构
|
||||
|
||||
> **原文**:[2025-06-17_大模型系列_深度解析_Prefill-Decode_分离式部署架构.md](./2025-06-17_大模型系列_深度解析_Prefill-Decode_分离式部署架构.md)
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/1918334902492963669
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:猫先生
|
||||
> **发布日期**:2025-06-17
|
||||
> **摘要日期**:2026-08-06
|
||||
> **价值评级**:⭐⭐ 中
|
||||
|
||||
---
|
||||
|
||||
## 核心命题
|
||||
|
||||
> **阶段特化** — 从 Prefill/Decode 两阶段的资源特性差异推导 PD 分离原理,并梳理其论文谱系与通信底座。
|
||||
|
||||
---
|
||||
|
||||
## 文章概要
|
||||
|
||||
本文是 Prefill-Decode 分离式部署的深度科普:先阐明 Prefill 计算密集(compute-bound)与 Decode 内存带宽密集(bandwidth-bound)的本质差异,解释 KV Cache"以存换算"的机理,再介绍 PD 分离原理与 NCCL/NIXL 通信协议,追溯 SARATHI、DistServe、LoongServe、Mooncake、Speculative Prefill、LServe 六篇论文的演进脉络,最后拆解 vLLM 的 Proxy/prefill/decode 三组件架构。价值在于概念讲解透彻、论文谱系完整并附源码链接,是入门 PD 分离的良好综述。局限是无一手实验数据,个别表述不够严谨(如"显存随上下文指数级上升"实为线性增长)。
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **两阶段资源特性根本不同** — Prefill 高并行、矩阵乘法为主、计算密集;Decode 逐 token 串行、频繁访问 KV Cache、内存带宽密集,这是 PD 分离的立论基础 `[分类: 共识]`
|
||||
2. **拆分的根本原因** — 输入 prompt 一次性完整提供、适合并行;输出 token 未知、只能逐个串行。KV Cache 复用使 Decode 的 attention 复杂度降低一个量级,实现"以存换算" `[分类: 共识]`
|
||||
3. **混合部署的资源错配** — 请求的 Prefill 长度与 Decode 长度不匹配时,同一 GPU 需同时承担高算力与高带宽需求,难以发挥最佳性能 `[分类: 共识]`
|
||||
4. **通信底座 NCCL 与 NIXL** — NCCL 适合单机/高带宽集群内的 GPU-GPU 通信;NIXL 是面向推理系统的"远程 NCCL"扩展层,专为跨节点 PD 分离的 KV Cache 远程传输设计 `[分类: 共识]`
|
||||
5. **论文谱系六连** — SARATHI(分块预填充+最大解码批处理,2023.8)→ DistServe(PD 解耦与 goodput 优化,2024.1)→ LoongServe(弹性序列并行,2024.4)→ Mooncake(KVCache 中心化分解架构,2024.6)→ Speculative Prefill(TTFT 加速,2025.2)→ LServe(混合稀疏注意力,2025.2) `[分类: 共识]`
|
||||
6. **vLLM 的 PD 分离三组件** — Proxy API server 负责路由,prefill 实例只生成 KV Cache,decode 实例执行 drop_select 获取 KV 并跳过 prefill 直接生成 token `[分类: 共识]`
|
||||
|
||||
---
|
||||
|
||||
## 批判性分析
|
||||
|
||||
### 假设前提
|
||||
|
||||
假设读者已具备 Transformer 与 KV Cache 基础知识;假设 PD 分离收益适用于大规模部署场景,而本文对硬件资源门槛与实施成本着墨不多。
|
||||
|
||||
### 论据与逻辑
|
||||
|
||||
以论文结论转述为主,出处清晰(六篇论文均附 arxiv 链接),作为综述论据充分;但"显存占用模式随上下文增长指数级上升"与 KV Cache 线性增长的客观事实不符,属表述疏漏,削弱了表格的严谨性。
|
||||
|
||||
### 边界与局限
|
||||
|
||||
仅一般性提及"适用于对时延有严格要求的场景",未讨论 P/D 配比、传输延迟隐藏、异构硬件等工程边界;对 PD 分离带来的系统复杂度与成本上升几乎未涉及。
|
||||
|
||||
---
|
||||
|
||||
## 可引用金句
|
||||
|
||||
> "Prefill 和 Decode 阶段不仅在结构上不同,在性能瓶颈上也大相径庭"
|
||||
|
||||
> "LLM生成文本的过程本质上是给定上下文,逐词预测下一个词。但在实现上,这个过程被明确地分成两个阶段"
|
||||
|
||||
---
|
||||
|
||||
## 总体评价
|
||||
|
||||
**亮点**:
|
||||
- 概念讲解由浅入深,Prefill/Decode 对比表格清晰直观
|
||||
- 论文谱系(2023.8–2025.2)梳理完整并附代码链接,索引价值高
|
||||
- NCCL/NIXL 通信协议对比实用
|
||||
|
||||
**不足**:
|
||||
- 无一手数据,全部结论为二手转述
|
||||
- 个别技术表述不严谨(显存增长量级)
|
||||
- 缺少 PD 分离局限、成本与适用边界的系统讨论
|
||||
|
||||
**适用场景**:初学者理解 PD 分离原理与演进脉络的入门综述;需要快速检索 PD 分离相关论文谱系的工程师。
|
||||
|
||||
**关联建议**:进阶阅读 DistServe(OSDI 2024)原论文及 Zoe Lee 的精读文章;实践侧阅读 akaihaoshuai 的 9 条实测结论与 vLLM/sglang 部署文档。
|
||||
|
||||
---
|
||||
|
||||
## 配图
|
||||
|
||||

|
||||
@@ -0,0 +1,197 @@
|
||||
# 大模型学习 | PD分离详解
|
||||
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:秋月如珪
|
||||
> **发布日期**:2026-02-02
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/2001354095441757984
|
||||
|
||||
---
|
||||
|
||||
## 一、什么是PD分离?
|
||||
|
||||
**PD分离**(Prefill-Decode Disaggregation)是一种将LLM推理过程中的**预填充(Prefill)阶段**与**解码(Decode)阶段**拆分到不同GPU/AI加速器实例上独立执行的架构设计。
|
||||
|
||||
在大模型推理中,一个完整的生成过程天然分为两个特征迥异的阶段:
|
||||
|
||||
**Prefill阶段(计算密集型)**
|
||||
|
||||
- **任务**:并行处理用户输入的整个Prompt(可能长达数千甚至数万token),计算所有token之间的注意力关系,生成**KV Cache**(键值缓存),并输出**第一个token**。
|
||||
- **特征**:计算量大、显存带宽压力相对较小、延迟指标为**TTFT**(Time To First Token,首token延迟,通常要求50-400ms)[1]。
|
||||
- **资源需求**:需要强大的计算能力(FLOPS),适合使用**张量并行(Tensor Parallelism)**加速。
|
||||
|
||||
**Decode阶段(内存密集型)**
|
||||
|
||||
- **任务**:基于Prefill生成的KV Cache,以**自回归方式**逐个生成后续token(每步只生成一个新token,并将其加入KV Cache继续下一步)。
|
||||
- **特征**:计算量小,但**显存带宽消耗极高**(频繁读取完整的KV Cache),延迟指标为**TPOT/TBT**(Time Per Output Token/Token Between Token,通常要求25-55ms)。
|
||||
- **资源需求**:需要高显存带宽和大容量显存,适合使用**数据并行(Data Parallelism)**提升吞吐。
|
||||
|
||||
传统的**Continuous Batching**将两个阶段混合在同一GPU上处理,导致资源竞争和相互干扰。PD分离通过**硬件解耦**,让两个阶段各自运行在最适合的硬件配置和优化策略下。
|
||||
|
||||
---
|
||||
|
||||
## 二、为什么需要PD分离?
|
||||
|
||||
### 1. 混合部署的资源冲突
|
||||
|
||||
当Prefill和Decode在同一个GPU上混合执行时会发生:
|
||||
|
||||
- **计算资源争抢**:Prefill的高计算需求会抢占Decode的执行时间,导致TPOT(token间延迟)抖动。
|
||||
- **显存压力叠加**:Prefill需要临时缓存大量中间结果,Decode需要常驻整个KV Cache,两者叠加容易导致OOM(显存溢出)。
|
||||
- **Batching策略冲突**:Prefill适合**小batch**(计算饱和后增加batch只会延长延迟),而Decode适合**大batch**(提升显存带宽利用率)。混合部署无法在两种策略间取得最优平衡。
|
||||
|
||||
### 2. SLO(服务等级目标)难以同时满足
|
||||
|
||||
实验数据显示:在单张A100上运行13B参数模型,当请求速率增加时:
|
||||
|
||||
- TTFT约束(0.4秒)可支持约**3 RPS**(每秒请求数)
|
||||
- TPOT约束(0.04秒)仅能支持约**1.6 RPS**
|
||||
|
||||
系统的**Goodput**(有效吞吐)由两者最小值决定,即**1.6 RPS/GPU**。混合部署存在明显的性能天花板。
|
||||
|
||||
### 3. 硬件资源浪费
|
||||
|
||||
Prefill阶段GPU计算单元满载但显存带宽闲置;Decode阶段显存带宽饱和但计算单元空闲。混合部署导致两种资源都无法充分利用。
|
||||
|
||||
---
|
||||
|
||||
## 三、PD分离的核心架构
|
||||
|
||||
### 基础工作流程
|
||||
|
||||
```
|
||||
请求 → [Prefill Worker: GPU集群A] → KV Cache传输 → [Decode Worker: GPU集群B] → 流式输出
|
||||
```
|
||||
|
||||
1. **请求路由**:新请求首先被路由到Prefill Worker,执行完整的Prompt计算,生成KV Cache和首个token。
|
||||
2. **状态迁移**:系统将KV Cache从Prefill Worker传输到Decode Worker(这是PD分离的核心技术挑战)。
|
||||
3. **解码生成**:Decode Worker加载KV Cache,持续执行自回归解码,直到生成结束符(EOS)或达到最大长度。
|
||||
|
||||
### 资源分配优势
|
||||
|
||||
通过分离,系统可以独立优化两个阶段:
|
||||
|
||||
- **Prefill集群**:配置高算力GPU(如A100/H100),采用张量并行降低TTFT。
|
||||
- **Decode集群**:配置高显存带宽GPU,采用大batch和数据并行提升吞吐。
|
||||
|
||||
实验表明,简单的**2P1D配置**(2个Prefill GPU + 1个Decode GPU)即可将Goodput提升至**3.3 RPS/GPU**,相比混合部署提升约**2倍**。
|
||||
|
||||
---
|
||||
|
||||
## 四、关键技术挑战与优化
|
||||
|
||||
### 1. KV Cache传输机制
|
||||
|
||||
Prefill完成后,需要将庞大的KV Cache(可能达数十GB)传输到Decode节点。传输粒度分为三级:
|
||||
|
||||
| 粒度 | 机制 | 优点 | 缺点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 请求级 | Prefill完成后一次性传输全部KV Cache | 传输次数少,开销低 | 大Prompt时传输延迟高,影响TTFT |
|
||||
| 层级 | 每计算完一层Transformer,立即异步传输该层KV Cache,同时计算下一层 | 传输与计算重叠,延迟隐藏效果好;可提前启动Decode | 小Prompt场景下同步开销可能超过收益(Splitwise方案) |
|
||||
| 块级 | 将Prompt分块处理,逐块传输 | 保持GPU计算饱和状态 | 实现复杂度高(TetriInfer方案) |
|
||||
|
||||
### 2. 高性能传输协议
|
||||
|
||||
为降低KV Cache传输延迟,业界开发了多种专用Connector:
|
||||
|
||||
- **SharedStorageConnector**:通过共享文件系统(NFS/本地磁盘)传递,实现简单但延迟高(毫秒级),适合测试环境。
|
||||
- **P2pNcclConnector**:基于NVIDIA NCCL实现GPU间点对点直接传输,绕过CPU内存,延迟最低。
|
||||
- **NixlConnector**:使用NVIDIA NIXL(Inference Xfer Library)库,支持GPU与异构内存(CPU DRAM、SSD)间的高速传输,实现分层KV缓存。
|
||||
- **LMCacheConnector**:支持将KV Cache卸载到远程存储(Redis、InfiniStore),实现跨请求、跨会话的KV Cache复用。
|
||||
|
||||
### 3. 独立Batching策略
|
||||
|
||||
- **Prefill侧**:保持**小batch size**(通常1-4个请求)。因为Prompt较长时,GPU计算已饱和,增加batch只会线性增加TTFT而不提升吞吐。
|
||||
- **Decode侧**:采用**大batch size**(可达64-128个请求)。因为Decode是显存带宽瓶颈,增大batch能提升计算强度(arithmetic intensity),显著提高吞吐。
|
||||
|
||||
### 4. 差异化并行策略
|
||||
|
||||
- **Prefill**:采用**张量并行(TP)**将模型层内部分割到多GPU,降低单层计算延迟,满足严格TTFT要求。
|
||||
- **Decode**:采用**流水线并行(PP)**或**数据并行(DP)**,因为Decode对延迟相对不敏感,更适合通过并行提升整体吞吐。
|
||||
|
||||
---
|
||||
|
||||
## 五、工业界实践案例
|
||||
|
||||
### 1. NVIDIA Dynamo
|
||||
|
||||
Dynamo是NVIDIA开源的推理框架,提供完整的PD分离解决方案:
|
||||
|
||||
- **Dynamo Planner**:智能监控TTFT和TPOT,动态决策是否启用PD分离及资源配比。
|
||||
- **Smart Router**:KV Cache感知的请求路由,最大化缓存命中率。
|
||||
- **NIXL库**:专为大模型推理设计的高性能传输库,支持毫秒级大批量KV Cache跨节点传输。
|
||||
|
||||
部署示例(Kubernetes):
|
||||
|
||||
```yaml
|
||||
apiVersion: nvidia.com/v1alpha1
|
||||
kind: DynamoGraphDeployment
|
||||
spec:
|
||||
services:
|
||||
VllmPrefillWorker:
|
||||
replicas: 2 # 2个Prefill实例
|
||||
VllmDecodeWorker:
|
||||
replicas: 1 # 1个Decode实例
|
||||
```
|
||||
|
||||
### 2. vLLM开源实现
|
||||
|
||||
vLLM在V1版本中引入了**KVConnector**抽象层,统一支持多种传输后端:
|
||||
|
||||
- **MultiConnector**:可同时向多个存储后端(本地+远程)写入KV Cache,提供数据冗余。
|
||||
- **Disaggregated Serving**:与Mooncake Store、LMCache集成,支持生产级PD分离部署。
|
||||
|
||||
### 3. llm-d(Kubernetes原生方案)
|
||||
|
||||
由IBM等贡献的llm-d项目,将PD分离与K8s深度集成:
|
||||
|
||||
- 基于**Inference Gateway**实现智能负载均衡。
|
||||
- 支持通过**NIXL**进行P/D实例通信。
|
||||
- 提供声明式API定义PD分离拓扑。
|
||||
|
||||
### 4. Mooncake(Kimi的推理平台)
|
||||
|
||||
Mooncake是最早大规模应用PD分离的工业级系统之一:
|
||||
|
||||
- **架构**:以KV Cache为中心的解耦架构,独立部署Prefill集群与Decode集群。
|
||||
- **创新**:利用集群空闲的CPU、DRAM和SSD资源,构建**分层KV Cache缓存池**。
|
||||
- **效果**:在长上下文场景中,吞吐量相比基线提升最高达**525%**;真实负载下可多处理**75%**的请求。
|
||||
|
||||
---
|
||||
|
||||
## 六、PD分离的适用场景与局限
|
||||
|
||||
### 最佳适用场景
|
||||
|
||||
1. **高并发在线服务**:当需要同时满足严格TTFT(用户体验)和TPOT(流式输出流畅度)时,PD分离几乎是目前唯一选择。
|
||||
2. **长上下文处理**:Prompt长度差异大(如RAG场景),PD分离可避免长Prefill阻塞短Decode。
|
||||
3. **成本敏感场景**:通过为不同阶段配置不同规格GPU(如Prefill用H100,Decode用L40S),显著降低推理成本。
|
||||
|
||||
### 局限与替代方案
|
||||
|
||||
- **overhead**:KV Cache传输引入额外延迟(虽然可通过层级传输隐藏)。
|
||||
- **系统复杂度**:需要维护两套集群、处理状态同步和故障恢复。
|
||||
- **替代方案**:对于延迟要求不极端的场景,**Chunked-Prefills**(将长Prompt分块与Decode交替执行)是更简单的折中方案。
|
||||
|
||||
---
|
||||
|
||||
## 七、总结
|
||||
|
||||
PD分离代表了LLM推理架构从**统一处理**向**阶段特化**演进的重要趋势。通过识别Prefill(计算密集)和Decode(内存密集)的本质差异,该架构打破了传统部署的性能瓶颈,实现了:
|
||||
|
||||
- **干扰隔离**:两个阶段独立运行,互不影响。
|
||||
- **资源最优**:针对不同阶段配置最适合的硬件和并行策略。
|
||||
- **吞吐飞跃**:Goodput可提升2-5倍,同时满足延迟SLO。
|
||||
|
||||
随着长文本(128K+)和多模态大模型的普及,推理负载的异构性将进一步加剧。PD分离不仅是当前的技术热点,更可能成为下一代大模型服务(如GPT-5、Claude 4)的**默认部署范式**。对于需要构建高性能LLM服务的企业和开发者,深入理解并应用PD分离架构已成为必备技能。
|
||||
|
||||
---
|
||||
|
||||
| 指标类型 | 测量对象 | 量级 | 典型场景 |
|
||||
| --- | --- | --- | --- |
|
||||
| 数据中心网络延迟 | 节点间数据包传输时间 | 微秒级 (μs) | GPU间RDMA通信、NVLink传输 |
|
||||
| TTFT (Time To First Token),首token延迟 | 从请求发起到首个token生成的完整时间 | 毫秒级 (ms) | 用户感知的首字响应时间 |
|
||||
| TPOT (Time Per Output Token)或TBT(Token Between Token),token间延迟 | 每生成一个token的完整计算时间 | 毫秒级 (ms) | 用户感知的流式输出速度 |
|
||||
|
||||
## 参考
|
||||
|
||||
1. ^一些关键延迟和量级见上面的表格(没搞明白怎么把表格插注释里只能这样……)
|
||||
@@ -0,0 +1,81 @@
|
||||
# 📊 文章摘要:大模型学习 | PD分离详解
|
||||
|
||||
> **原文**:[2026-02-02_大模型学习_PD分离详解.md](./2026-02-02_大模型学习_PD分离详解.md)
|
||||
> **原文链接**:https://zhuanlan.zhihu.com/p/2001354095441757984
|
||||
> **来源**:知乎专栏
|
||||
> **作者**:秋月如珪
|
||||
> **发布日期**:2026-02-02
|
||||
> **摘要日期**:2026-08-06
|
||||
> **价值评级**:⭐⭐ 中
|
||||
|
||||
---
|
||||
|
||||
## 核心命题
|
||||
|
||||
> **阶段解耦** — 系统讲解 PD 分离的动机、传输机制与工业实践,并给出明确的适用边界与替代方案。
|
||||
|
||||
---
|
||||
|
||||
## 文章概要
|
||||
|
||||
本文系统讲解 PD 分离:从混合部署的计算争抢、显存叠加、batching 冲突说明动机,用 A100/13B 的 SLO 数据(TTFT 约束约 3 RPS、TPOT 约束约 1.6 RPS)说明 Goodput 由双指标最小值决定;随后展开 KV Cache 三级传输粒度(请求级/层级/块级)、四种传输 Connector、独立 batching 与差异化并行策略,并对比 Dynamo、vLLM、llm-d、Mooncake 四大工业实践。价值在于结构完整、决策导向,且专门讨论了局限与 Chunked-Prefills 折中方案。局限是多数数据未标注来源,对未来"默认部署范式"的预测偏乐观。
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **混合部署三类冲突** — 计算资源争抢致 TPOT 抖动、Prefill 中间结果与 KV Cache 显存叠加易 OOM、batching 策略冲突(Prefill 适合小 batch,Decode 适合大 batch)`[分类: 共识]`
|
||||
2. **Goodput 由双 SLO 的较紧者决定** — A100/13B 下 TTFT(0.4s)可支持约 3 RPS、TPOT(0.04s)仅约 1.6 RPS;2P1D 配置可将 Goodput 提升至 3.3 RPS/GPU,约 2 倍 `[分类: 共识]`
|
||||
3. **KV Cache 传输三级粒度** — 请求级实现简单但大 prompt 传输延迟高;层级可传输计算重叠、提前启动 Decode,但小 prompt 场景同步开销可能超过收益(Splitwise);块级保持 GPU 计算饱和但实现复杂度高(TetriInfer)`[分类: 共识]`
|
||||
4. **独立 batching 策略** — Prefill 保持小 batch(1-4 请求)避免线性增加 TTFT;Decode 采用大 batch(64-128)提升计算强度与带宽利用率 `[分类: 共识]`
|
||||
5. **差异化并行** — Prefill 用张量并行满足严格 TTFT,Decode 用流水线/数据并行提升吞吐 `[分类: 共识]`
|
||||
6. **工业界四案例** — Dynamo(Planner 动态决策 + Smart Router 缓存感知路由 + NIXL)、vLLM V1(KVConnector 抽象 + MultiConnector 冗余)、llm-d(K8s 原生 + Inference Gateway)、Mooncake(分层 KV Cache 池,长上下文吞吐最高提升 525%)`[分类: 共识]`
|
||||
7. **明确局限与替代方案** — KV 传输 overhead、双集群状态同步与故障恢复复杂度;延迟要求不极端的场景 Chunked-Prefills 是更简单的折中 `[分类: 共识]`
|
||||
|
||||
---
|
||||
|
||||
## 批判性分析
|
||||
|
||||
### 假设前提
|
||||
|
||||
假设读者关注高性能 LLM 服务的生产级部署;假设 TTFT/TPOT 双 SLO 是服务首要优化目标;假设两阶段硬件解耦的成本可控。
|
||||
|
||||
### 论据与逻辑
|
||||
|
||||
SLO 数据直观且有推导逻辑(Goodput 取两者最小值),但未标注出处(疑似来自 DistServe 论文),削弱了可信度;Mooncake 的 525% 与 75% 数据有论文支撑,其余性能数字(如 2 倍 Goodput 提升)缺乏来源。
|
||||
|
||||
### 边界与局限
|
||||
|
||||
作者专门列出局限与替代方案,边界意识较好;但"PD 分离可能成为下一代大模型服务的默认部署范式"属个人预测,缺乏论证,与 akaihaoshuai 实测中"普通场景没必要折腾"的结论存在张力。
|
||||
|
||||
---
|
||||
|
||||
## 可引用金句
|
||||
|
||||
> "系统的Goodput(有效吞吐)由两者最小值决定,即1.6 RPS/GPU。"
|
||||
|
||||
> "PD分离代表了LLM推理架构从统一处理向阶段特化演进的重要趋势。"
|
||||
|
||||
---
|
||||
|
||||
## 总体评价
|
||||
|
||||
**亮点**:
|
||||
- 知识结构完整(动机→机制→协议→实践→边界),传输粒度三级表格与 Connector 对比实用
|
||||
- 有独立的"局限与替代方案"章节,Chunked-Prefills 折中建议实操性强
|
||||
- 四大工业实践(Dynamo/vLLM/llm-d/Mooncake)覆盖了当前主流方案
|
||||
|
||||
**不足**:
|
||||
- 关键性能数据缺出处,需溯源验证
|
||||
- 个别技术细节与来源论文混编(如 Splitwise、TetriInfer 方案名)
|
||||
- "默认部署范式"等预测性论断缺乏论证支撑
|
||||
|
||||
**适用场景**:需要系统建立 PD 分离知识框架的工程师与学习者;PD 分离方案调研与技术汇报的材料底稿。
|
||||
|
||||
**关联建议**:数据溯源阅读 DistServe 论文原文;实践侧对照 akaihaoshuai 的实测阈值与极客博哥的架构决策清单;跟进 vLLM Disaggregated Serving 与 Dynamo 官方文档。
|
||||
|
||||
---
|
||||
|
||||
## 配图
|
||||
|
||||

|
||||
Reference in New Issue
Block a user