昇腾部署第 D4 课:PD 分离与混部——为什么把 Prefill 和 Decode 拆开
编制:观澜|日期:2026-10-05|级别:T2 标准级 层级:D 层 · L3 服务(D 层第 4 课,前接 D3《MindIE Motor》) 素材来源:昇腾官方 MindIE 3.1.0 文档(《PD 分离说明》《PD 分离架构说明》《HIXL 单边通信库》《服务部署方式说明》) 数据纪律:阶段定义、优势、架构要素、部署形态逐字出自官方文档;标注「归纳」的是便于记忆的整理,非官方口径。
第一段 · 章前定位
D3 提到过 PD 分离与 PD 混部,并给了一张对照表 ——
| 部署模式 | Engine 容器 | 跨角色 KV 传输 |
|---|---|---|
| PD 分离 | Prefill 和 Decode 容器 | 需要 |
| PD 混部 | union 容器 | 不需要 |
当时留了一个问题没答:
为什么要把 Prefill 和 Decode 拆开? 拆开为什么要付出"KV 传输"这个代价?
这一课回答它。而答案的关键,是这两个阶段的"性格"完全不同。
为什么这一课值得单独讲:
- 它是 L3 服务层最核心的架构概念之一 —— 官方在 MindIE Motor 里反复提到它("增强 PD 分离服务的能力")。
- 它决定了很多部署选择的走向:资源怎么配、网络怎么搭、KV 存储要不要上。
- C 层已经给它铺过路了 —— C3 讲过"图模式 / 单算子模式",那是单个请求怎么算; PD 分离是"多个请求怎么排队算" —— 从微观走到了宏观。
第二段 · 学习目标
学完这一课,你应该能回答:
- Prefill 和 Decode 各在做什么(官方定义)
- 这两个阶段的"性格差别"是什么——为什么说一个计算密集、一个访存密集
- PD 分离在解决什么问题("不分离"会怎样)
- 官方给出的三条优势分别是什么
- PD 分离是个集群架构——它需要哪三个必要元素
- 分离的代价:KV Cache 传输为什么绕不过去
第三段 · 两个阶段:官方定义(本课的基础)
官方原文(《PD 分离说明》):
Prefill 阶段:对输入 prompt 执行一次完整前向传播,生成初始隐藏状态(Hidden States), 计算密集型;每个新输入序列都需执行一次 Prefill。
Decode 阶段:基于 Prefill 结果逐步生成后续 token,每步仅计算最新 token 的激活与 attention, 单步计算量较小,但需反复执行直至生成结束,访存密集型(以 KV Cache 等内存访问为主)。
把这两段话拆成对照表(归纳)
| Prefill | Decode | |
|---|---|---|
| 干什么 | 处理输入 prompt,一次完整前向 | 逐 token 往后生成 |
| 产出 | 初始隐藏状态 | 后续 token |
| 特性(官方用词) | 计算密集型 | 访存密集型 |
| 执行次数 | 每个新输入序列执行一次 | 反复执行直到生成结束 |
| 每次的"量" | 一次很大(整个 prompt) | 单步计算量较小,但次数多 |
| 内存访问 | —— | 以 KV Cache 等内存访问为主 |
⭐ 用一句话记住两者的差别(归纳)
Prefill 是"一次性把题读懂",Decode 是"一个字一个字往外写"。
- 读题:输入很长,要一次算完 → 吃算力(计算密集)
- 写字:每次只写一个字,但要写很多字,且每次都要回看前面 → 吃内存带宽(访存密集)
"回看前面"这件事就是 KV Cache(官方原文:Decode 阶段"以 KV Cache 等内存访问为主")—— Decode 的每一步都要访问它。
⭐ 记住这一组词就够了: Prefill = 计算密集;Decode = 访存密集。 这一课的其余部分,都是从这一句话推出来的。
第四段 【如果我来做】一条真实的执行路径:先判断"值不值得拆"
这一节是本课的核心。 前三段讲的是"两个阶段分别是什么";这一节讲的是:如果现在把"PD 分离"这件事交给我,我从哪里开始、按什么顺序做、每一步凭什么判断。
4.0 我会按这个顺序做(八步)
① 先摸底 —— 先判断"值不值得拆":不装任何东西,先把 Prefill 计算密集 / Decode 访存密集(第三段)这两个事实对上你的负载和硬件,再决定要不要拆。
② 定方案(做哪一种):单机 PD 分离 / 多机 PD 分离 / PD 混部三选一,别默认上全套。
③ 确认集群三要素齐了:调度器 Coordinator + Prefill 实例 + Decode 实例,缺一不可(第六段)。
④ 规划 KV Cache 传输路径:拆开就有代价 —— Prefill 算出的 KV Cache 必须搬到 Decode,这条路要先想清楚(第七段)。
⑤ 动手起服务,每步立刻验:建命名空间 → 拉起集群 → kubectl get pods 看状态,一步一验,不攒着一起验。
⑥ 联调:发一个真实请求:看 P 算完 D 是否接着生成;接不上,就是"搬的环节"出了问题。
⑦ 出证据:留下 Pod 状态、global_ranktable.json、流式响应,给别人能复现。
⑧ 诚实:官方没给性能数字的地方,明写"这里要自己查"。
为什么把①放最前:① 是这几步里唯一"不可返工"的判断 —— 负载本来就小、机器也不多时,拆开反而更慢(多出来的那趟 KV 传输白搭)。所以先查事实,再决定拆不拆。下面 4.1 先把"为什么'不拆'会有问题"说清,4.2 给出要敲的命令和会看到的结果。
4.1 第①步 · 值不值得拆:为什么"不拆"会有问题
官方的说法(原文):
PD 分离……将大语言模型推理的预填充(Prefill)与解码(Decode)两个阶段拆分到不同实例上运行, 适用于对时延和吞吐要求较高的场景。通过 PD 分离可提高 NPU 利用率, 减轻 Prefill 与 Decode 分时复用带来的相互干扰,在相同时延下提升整体吞吐。
官方在另一处(PD 分离架构说明)又说了一遍:
该架构将推理的 2 个阶段(Prefill 和 Decode)分别部署到不同的实例上进行计算, 从而减少 Prefill 和 Decode 之间互相干扰,提升推理性能。
"分时复用"与"互相干扰"是什么意思(归纳):
混部(union)时,Prefill 和 Decode 在同一个实例上"轮着用"同一批卡。 问题在于两者的性格相反(第三段的结论):
| 需要什么 | 混在一起会怎样 | |
|---|---|---|
| Prefill | 大量算力 | 它一上来就占满算力,把 Decode 挤住 |
| Decode | 大量内存带宽 | 它要持续占用带宽,也被 Prefill 打断 |
归纳:一个吃算力、一个吃带宽 —— 混在一起时,两边的强项都用不满,还要互相等。 这就是官方说的"分时复用带来的相互干扰"。
类比(归纳,帮理解): 一家餐厅,厨师(算力)和服务员(带宽)是两拨人。 混部 = 同一个人又当厨师又当服务员 —— 炒菜时没人端菜,端菜时没人炒菜。 分离 = 分成两个岗,各干各的,同时进行。
一个直接的后果:吞吐(官方原文):
吞吐能力提升:Prefill 处理新请求的同时,Decode 可持续处理已有请求的解码, 整体处理能力更高。
归纳:分离之后,"读新题"和"写旧文"可以同时发生 —— 这是吞吐提升最直观的来源。
这一步怎么落到我的判断上:把上面的"性格差别"对回自己的场景 —— 并发高、对时延敏感、机器和网络都够,就值得拆;只是想把服务先跑通、机器只有一台,就别拆(更细的选型见第五段)。
4.2 第⑤⑥步 · 起服务与联调(命令 + 结果)
以下命令逐字出自官方 MindIE 3.1.0《PD分离服务部署 · 使用 kubectl 部署单机 PD 分离服务示例》(原文路径:zh/mindie/310/mindiellm/llmdev/mindie_motor_cpp/user_guide/service_deployment/pd_separation_service_deployment.md)。
它们都要在部署脚本目录 examples/kubernetes_deploy_scripts 下执行(官方明说:不在该目录下会报错)。
命令 kubectl create namespace mindie
含义:给 PD 分离集群建一个 K8s 命名空间(官方示例默认名
mindie) 拆解:kubectl(K8s 命令行工具)+create namespace(创建命名空间)+mindie(名字,可换成你自己的,后面命令跟着换) 用法:首次部署必建;也可写成kubectl create namespace <你的名称>期望:回显namespace/mindie created不过会怎样:报Error from server (AlreadyExists)→ 该命名空间已建过,直接进下一步;报连接类错误 →kubectl没配好 kubeconfig,或你不在 K8s 管理节点上(官方要求由集群管理员在管理节点执行)
命令 bash deploy.sh 800i_a2
含义:一键拉起单机 PD 分离集群(Controller / Coordinator / Server 三组件由这一个脚本下发) 拆解:
bash(执行脚本)+deploy.sh(部署入口脚本)+800i_a2(机型参数) 用法:官方给三种写法 ——bash deploy.sh(默认)/bash deploy.sh 800i_a2(Atlas 800I A2 推理服务器)/bash deploy.sh 800i_a3(Atlas 800I A3 超节点服务器);跑前先export MINDIE_USER_HOME_PATH={镜像的安装路径}指向镜像里 MindIE 的安装父目录 期望:脚本自动下发业务配置、自动生成 global_ranktable、自动把 Pod 调度到计算节点 不过会怎样:路径类报错 → 先核MINDIE_USER_HOME_PATH;配置字段非法 → 官方建议先用 MindStudio 预检工具校验配置文件再看部署脚本
命令 kubectl get pods -n mindie
含义:查看 PD 集群里所有 Pod 的状态 拆解:
get pods(列出 Pod)+-n mindie(限定命名空间mindie) 用法:直接执行;想持续观察加-w期望:Controller、Coordinator、Server 都启动在"以mindie-server开头的 Pod"里;READY 1/1、STATUS Running不过会怎样:出现Pending/ErrImagePull/CrashLoopBackOff→ 记下现象回第八段排查;⚠️Running只代表容器被调度起来了,不代表业务程序启动成功 —— 还要看日志(下一条)
命令 bash log.sh
含义:一键查询这个部署脚本拉起的所有 Pod 的标准输出日志 拆解:
bash log.sh(脚本示例自带的日志查询脚本) 用法:只看某一个 Pod 用kubectl logs mindie-server-7b795f8df9-vl9hv -n mindie(把 Pod 名换成kubectl get pods里看到的实际名字) 期望:日志里输出生成了global_ranktable.json(含server_group_list、server_list等) 不过会怎样:日志里没有 ranktable、或报通信错误 → 多半是参数面互联没通(官方要求服务器 NPU 卡对应的端口处在同一个 VLAN、可通过 RoCE 互通),或 P 节点与 D 节点的 NPU 卡数不一致
命令 bash generate_stream.sh
含义:用 curl 向推理入口发一个流式请求,验端到端能不能出 token 拆解:
generate_stream.sh(脚本示例自带的流式响应示例;chat.sh是简单对话版) 用法:先把脚本里的 IP 改成"集群管理节点宿主机 IP";Coordinator 走 HTTPS 就配证书,走 HTTP 就把脚本里的 HTTPS 改成 HTTP 并删掉证书相关配置 期望:逐 token 流式返回生成结果(官方:部署成功后节点开放 31015 端口作为推理业务接口) 不过会怎样:连不上 → 先查 31015 端口和脚本里的 IP 填对没;能连但迟迟不出结果 → 卡在"搬的环节"(KV Cache 没从 P 传到 D)或 P/D 有一侧其实没起来(回第八段)
命令 bash delete.sh mindie ./
含义:一键卸载已部署的 PD 集群(改配置重部署前要先卸载) 拆解:
bash delete.sh+mindie(命名空间,按实际替换)+./(路径参数) 用法:必须在该脚本所在的examples/kubernetes_deploy_scripts目录下执行 期望:相关 Pod 被删除、集群停止 不过会怎样:报错、服务停不掉 → 十有八九是没在脚本目录下执行(官方明说:否则无法停止服务并报错)
第五段 · 官方给出的三条优势(原文,逐条)
官方《PD 分离说明》的"主要优势"一节,原文如下:
① 资源利用更优
Prefill 为计算密集型、Decode 为访存密集型,特性不同, 分离部署可更充分利用 NPU 的计算与带宽资源。
② 吞吐能力提升
Prefill 处理新请求的同时,Decode 可持续处理已有请求的解码,整体处理能力更高。
③ 时延更可控
两阶段分离可减少排队与等待,尤其在高并发场景下有助于降低时延。
三条优势的内在逻辑(归纳)
① 资源利用更优 ← 因为两者一个吃算力、一个吃带宽,分开才能各自用满
↓
② 吞吐提升 ← 因为可以同时进行(读新题 & 写旧文)
↓
③ 时延更可控 ← 因为不再互相排队等
三条优势不是并列的三个好处,而是同一件事的三个侧面。
⚠️ 一个必须说清的边界
官方的三条优势,前提都是"对时延和吞吐要求较高的场景"(原文如此)。
归纳:PD 分离不是"总是更好"(归纳):
| 场景 | 更合适 |
|---|---|
| 高并发、追求吞吐、对时延敏感 | PD 分离(官方原文:适用于对时延和吞吐要求较高的场景) |
| 需要独立规划 P/D 资源 | PD 分离(官方《服务部署方式说明》:"适用于需要独立规划 P/D 资源、追求更高吞吐的场景") |
| 小规模、先跑通、没有多余的机器 | PD 混部(更简单:一个 union 容器,不需要跨角色 KV 传输) |
这与 B4/C1 的思路一致:先按最简单的跑通,再按需要上复杂度。
第六段 · PD 分离是个集群架构:三个必要元素
官方原文(《PD 分离架构说明》):
PD 分离是集群化架构,集群中,存在三种必要的元素,如下所示: - 调度器(Coordinator) - Prefill 实例(P) - Decode 实例(D)
对照 D3 的五个子组件(归纳)
D3 讲过 Motor 的五个子组件 —— 现在看它们在 PD 分离里各站什么位置:
| PD 分离的必要元素 | 对应 D3 的哪个组件 | 干什么 |
|---|---|---|
| 调度器 Coordinator | Coordinator(D3) | 接收请求,调度到 P 或 D 实例 |
| Prefill 实例(P) | Server 侧(EngineServer + 引擎) | 跑 Prefill |
| Decode 实例(D) | Server 侧(EngineServer + 引擎) | 跑 Decode |
⭐ 这就是 D3 那句"Coordinator 是数据流枢纽"的实际含义 —— 它是 P 和 D 之间的那个调度中枢。
官方给的参考部署方案(原文)
官方在《PD 分离说明》里说明了本仓库采用的方案:
本仓库采用多机 PD 分离部署方案:通过 K8s Service 为 Coordinator 暴露推理入口, 使用多个 Deployment 分别部署 Controller(单 Pod)、 Coordinator(单 Pod)以及 Server(P 实例与 D 实例各若干 Pod)。 Controller 负责集群与实例管理,Coordinator 接收用户请求并调度至 P/D 实例, 由 P 实例与 D 实例协同完成一次完整推理。
归纳这个方案的形状(归纳):
[ K8s Service ] ← 对外暴露推理入口
│
▼
Coordinator(单 Pod) ← 调度中枢
│ │
┌────────────┘ └────────────┐
▼ ▼
Server: P 实例(若干 Pod) Server: D 实例(若干 Pod)
└────────── 协同完成一次完整推理 ──────────┘
▲
Controller(单 Pod)← 集群与实例管理
注意两件事(归纳):
- P 和 D 都是"若干 Pod" —— 可以水平扩展(这也回应了官方说的"需要独立规划 P/D 资源")
- Controller 和 Coordinator 都是"单 Pod" —— 控制面是单点(这也解释了为什么官方单独强调 RAS 能力)
第七段 · 分离的代价:KV Cache 传输
D3 留的钩子在这里解 —— 为什么 PD 分离"需要跨角色 KV 传输"。
官方原文(《LLM DataDist》/《HIXL 单边通信库》)
大模型推理 PD 分离式框架中,Prefill 阶段生成的 KV Cache 需要传输到 Decode, 然后 Decode 阶段进行增量迭代推理。 LLM-DataDist 作为大模型分布式集群和数据管理组件, 通过简易的 API 开放给用户……
推理一下"为什么必须传"(归纳)
把第三段的结论连起来:
Prefill 在 P 实例上算完 → 产生了 KV Cache(第三段:Decode 要"回看前面")
Decode 在 D 实例上继续生成 → 它需要"回看前面"的那些内容
但两者在不同实例上 → 所以 KV Cache 必须搬过去
⭐ 一句话:
拆开是有代价的 —— 原来在同一个实例里"直接就能看到"的东西,现在要跨网络搬。
这也解释了 D3 那张对照表里的两列: - PD 分离:跨角色 KV 传输 需要 - PD 混部:不需要(因为压根没拆开)
由此引出的两类组件(归纳)
官方文档里与这件事相关的名字:
| 名字 | 官方定位 | 在哪一层 |
|---|---|---|
| KV Cache Store | D3 提到"按需拉起 KV Cache Store" | Motor 侧的部署概念 |
| LLM-DataDist | "大模型分布式集群和数据管理组件" | CANN 侧(CANN 的更多组件里) |
| HIXL 单边通信库 | CANN 的通信库之一(B1/A3 的 ops 包里提到过 HIXL) | L1(CANN) |
⭐ 注意这里的层次跨度: PD 分离这件事,从 L3(Motor 的部署)一直穿到 L1(HIXL 通信库)。 这就是为什么"部署"这门手艺难 —— 一个架构决策会牵动好几层。
回想 A3 讲的 HDK 四件套、B1 讲的 NNAL: HIXL 单边通信库正是 ops 包里包含的库之一 —— 它在 P 和 D 之间搬数据这件事上派上用场。
规划 KV Cache 传输路径时,我会先问三个问题(归纳)
把八步里的第 ④ 步落到实处:
- 搬的是什么、从哪搬到哪 —— Prefill 实例上生成的 KV Cache,要搬到 Decode 实例(官方原文)。
- 用什么搬 —— 官方相关的名字有两个层次:Motor 侧的 KV Cache Store(D3 提到"按需拉起")、 CANN 侧的 LLM-DataDist / HIXL 单边通信库(本课只给定位,用法以各自官方文档为准)。
- 这条路的物理条件够不够 —— 官方对多机 PD 分离明确要求 NPU 网口互联(带宽 200Gbps), 且集群必须具备参数面互联(NPU 卡对应端口处在同一个 VLAN,可以通过 RoCE 互通)。 这条不满足,"搬"一定出问题 —— 也正是 4.2 里日志报通信错时要先查的地方。
⚠️ 一句话:KV Cache 的传输路径,是 PD 分离里唯一"因为拆开才多出来"的东西; 它规划不好,前面省下的时间会在这里还回去。
第八段 · 出问题怎么查
先做"选型判断":该分离还是该混部
按官方的适用条件照镜子(归纳):
| 你的情况 | 建议 |
|---|---|
| 高并发、要吞吐、时延敏感 | PD 分离 |
| 需要独立规划 P/D 的资源 | PD 分离 |
| 机器够、网络好 | PD 分离 |
| 先跑通 / 机器少 / 不想引入 KV 传输 | PD 混部(一个 union 容器) |
分离场景的排查方向(归纳)
| 现象 | 先查什么 |
|---|---|
| P 或 D 有一边起不来 | 各实例的 Pod / 容器状态;NodeManager 管这个(D3) |
| 请求进不来 | Coordinator(统一入口)+ K8s Service(官方方案里由它暴露入口) |
| P 算完了但 D 不接着生成 | KV Cache 传输那条路(跨角色传输 / KV Cache Store) |
| 部分卡在等 | 资源规划:P 和 D 的资源配比是否合理 |
| 想让 P/D 各自扩容 | 官方方案里 P/D 是若干 Pod,可水平扩展 |
| 混部改分离后性能反而差 | 分离有代价:多了 KV 传输;小规模时不一定划算 |
⭐ 一个最省时间的判断法
PD 分离出的问题,先分清是"算的环节"还是"搬的环节"。
| 类型 | 表现(归纳) | 方向 |
|---|---|---|
| 算的环节 | 某一侧实例没起来 / 起了但报错 | 实例本身(回到 D2/D3) |
| 搬的环节 | 两边都活着,但卡在中间;或结果接不上 | KV 传输 / KV Cache Store / HIXL |
"算的不行"和"传的不行"是两种病 —— 分离架构把这两种病分开了, 所以排查时也要先把它们分开。
常见报错清单(按现象查)
⚠️ 数据纪律提示:官方在本课涉及的部署文档里没有单独收录"报错原文清单", 下表全是由官方给出的限制与约束推出的按现象排查的方向,不含编造的报错文本。 真正的报错原文,请用官方故障案例库按实际报错的特征词检索(入口见附录 A)。
| 现象 | 先归到哪一类 | 先查什么 |
|---|---|---|
kubectl get pods 里 P 或 D 实例起不来 |
算的环节 | 各实例的 Pod / 容器状态(Pod 生命周期归 NodeManager 管,见 D3) |
Pod 一直是 Pending |
算的环节 | 计算节点资源够不够、nodeSelector 选中的节点对不对、卡有没有被占 |
Pod 是 ErrImagePull / ImagePullBackOff |
算的环节 | 镜像名(官方:mindie_server.yaml / mindie_ms_coordinator.yaml / mindie_ms_controller.yaml 里的 image)能不能拉到 |
Pod Running 但业务没起来 |
算的环节 | 看日志:bash log.sh 或 kubectl logs <pod> -n mindie |
日志里没有 global_ranktable.json / 报通信错 |
算的环节 | 参数面互联(NPU 网口同 VLAN、RoCE 互通);P、D 卡数是否一致 |
| 请求进不来 | 算的环节 | Coordinator(统一入口)+ K8s Service(官方方案里由它暴露入口) |
| 能连上但一直不出结果 | 搬的环节 | KV Cache 传输那条路(跨角色传输 / KV Cache Store / HIXL,见第七段) |
| P 算完了但 D 不接着生成 | 搬的环节 | 同上:KV Cache 有没有从 P 传到 D |
| 部分卡在等 | 算的环节 | 资源规划:P 和 D 的资源配比是否合理(官方 default_p_rate / default_d_rate) |
| HTTPS 开了之后服务被 K8s 反复重启 | 算的环节 | 官方提示:启用 TLS 时要在 controller_init.yaml、coordinator_init.yaml 里删掉三项健康探针,否则可能被频繁重启 |
| 部署脚本跑不起来 / 卸载失败 | 算的环节 | 必须在 examples/kubernetes_deploy_scripts 目录下执行(官方明说否则报错) |
| 用的模型/特性不支持 | 算的环节 | 官方限制:单机仅 Atlas 800I A2/A3;LLaMA3-8B / Qwen2.5-7B / Qwen3-8B 支持;不与 Prefix Cache、稀疏量化、KV Cache int8 量化同时用 |
第九段 · 小结与下一课
三句话带走
- Prefill 是计算密集型(一次性读懂整个 prompt),Decode 是访存密集型(一个字一个字往外写,每步都要回看 KV Cache)。 性格相反,所以混在一起会互相干扰。
- PD 分离的官方三条优势:资源利用更优(算力与带宽各自用满)、 吞吐能力提升(读新题与写旧文可同时进行)、时延更可控(减少排队等待)—— 三者是同一件事的三个侧面。
- PD 分离是集群架构,三种必要元素:调度器(Coordinator)、Prefill 实例、Decode 实例; 代价是 Prefill 生成的 KV Cache 必须传到 Decode —— 这件事从 L3 一路穿到 L1 的通信库。
本课在体系里的位置
─── L0 硬件与环境(A 层,已完成)─── A0 / A1 / A2 / A3
─── L1 基础软件(B 层,已完成)─── B1 / B2 / B3 / B4 / B5
─── L2 框架(C 层,已完成)─── C1 / C2 / C3
─── L3 服务(D 层)───
D1 L3 服务层:推理服务是怎么跑起来的 ✅
D2 vLLM Ascend:把推理服务真正跑起来 ✅
D3 MindIE Motor:五个子组件与集群的骨架 ✅
D4 PD 分离与混部:为什么把 P 和 D 拆开 ★ 本课
D5(拟)服务的起停、端口与调优
─── 排障(E 层)─── E1
本课留下的"钩子"
| 钩子 | 在哪一课填 |
|---|---|
| 服务怎么扩缩容、限流、主备倒换 | D5 |
| 虚推健康检查、KV Cache 亲和调度、KV 池化(官方 Motor 运维章节提到) | D5 / 后续 |
| HIXL / LLM-DataDist 的完整用法 | CANN 通信库文档 |
| 量化(msModelSlim)属于 L4 应用层 | D 层之后 |
课后自测(3 题)
- Prefill 和 Decode 各是"什么密集"?为什么?这一条为什么能推出后面的所有结论?
- 用"餐厅"之外的一个类比,说明"分时复用带来的相互干扰"是什么。
- PD 分离之后为什么必须传 KV Cache?这个代价在什么情况下可能不划算?
附录 A · 本课引用的官方出处
| 内容 | 出处 |
|---|---|
| PD 分离的定义、「提高 NPU 利用率、减轻分时复用带来的相互干扰、在相同时延下提升整体吞吐」 | 官方 MindIE《PD 分离说明》zh/mindie/310/mindiemotor/motordev/docs/zh/user_guide/features/pd_disaggregation.md |
| Prefill / Decode 两阶段的官方定义(计算密集型 / 访存密集型 / Hidden States / KV Cache) | 同上 |
| 多机 PD 分离部署方案(K8s Service、多个 Deployment、Controller 单 Pod、Coordinator 单 Pod、Server 的 P/D 各若干 Pod) | 同上 |
| PD 分离的三条主要优势(资源利用更优 / 吞吐能力提升 / 时延更可控) | 同上 |
| 「PD 分离是集群化架构,存在三种必要的元素:调度器(Coordinator)、Prefill 实例(P)、Decode 实例(D)」 | 官方《PD 分离架构说明》zh/mindie/310/mindiellm/llmdev/mindie_llm0044.html |
| 「将推理的 2 个阶段分别部署到不同实例,减少互相干扰,提升推理性能」 | 同上 |
| 「Prefill 阶段生成的 KV Cache 需要传输到 Decode,然后 Decode 阶段进行增量迭代推理」;LLM-DataDist 的定位 | 官方 CANN《LLM DataDist 开发(Python)· 概述》zh/CANNCommunityEdition/920beta2/others/llmdatadistdev/docs/zh/user_guides/llm_datadist/llm_datadist_dev/python/introduction.md |
| HIXL 单边通信库与 PD 分离式框架的关系 | 官方 CANN《HIXL 单边通信库 · 概述》zh/CANNCommunityEdition/920beta2/commlib/hixlug/docs/zh/guide/python/introduction.md |
| PD 分离「适用于需要独立规划 P/D 资源、追求更高吞吐的场景」(业务拓扑) | 官方 MindIE《服务部署方式说明》zh/mindie/310/mindiemotor/motordev/docs/zh/user_guide/deployment/k8s/README.md |
| 官方故障案例库入口 | https://www.hiascend.com/document/caselibrary |
⚠️ 数据纪律提示: ① 本课未给出任何性能数字(如吞吐提升倍数、时延下降幅度)—— 官方在《PD 分离说明》中未给出量化数据,故不编造; ② 计算密集/访存密集是官方原文用词;更深的硬件原理本课未展开; ③ KV Cache Store / LLM-DataDist / HIXL 的具体用法本课只给定位,用法以各自官方文档为准; ④ 标注「归纳」的内容(餐厅类比、三条优势的逻辑链、两张判断表)非官方口径。
附录 B · 本课出现的名词详解
Prefill(预填充)
- 官方定义:对输入 prompt 执行一次完整前向传播,生成初始隐藏状态(Hidden States)
- 特性:计算密集型
- 频次:每个新输入序列都需执行一次
Decode(解码)
- 官方定义:基于 Prefill 结果逐步生成后续 token,每步仅计算最新 token 的激活与 attention
- 特性:单步计算量较小,但需反复执行直至生成结束;访存密集型(以 KV Cache 等内存访问为主)
KV Cache
- 它是什么(结合官方原文化解):Decode 阶段"要回看前面"所依赖的那份缓存
- 在 PD 分离中的角色:Prefill 生成它 → 传输给 Decode → Decode 用它做增量迭代推理
- 为什么它是关键:它既是 Decode 性能的依赖,也是 PD 分离的代价来源
增量迭代推理
- 官方原文用词:「Decode 阶段进行增量迭代推理」
- 归纳:每次只新增一个 token,在已有结果上往前推一步(不是每次都重算全部)
分时复用
- 官方原文用词:「减轻 Prefill 与 Decode 分时复用带来的相互干扰」
- 归纳:同一份资源被两个阶段轮流占用(混部时的状态)
名词速查表
| 名词 | 一句话 |
|---|---|
| Prefill | 一次性读懂 prompt,计算密集 |
| Decode | 逐 token 生成,访存密集 |
| KV Cache | Decode 要回看的缓存;PD 分离要传的就是它 |
| 分时复用 | 两个阶段轮流用同一份资源(混部) |
| PD 分离 | 拆成 P 实例 + D 实例,需要跨角色 KV 传输 |
| PD 混部 | 一个 union 容器,不需要 KV 传输 |
| Coordinator | PD 分离的调度器(三种必要元素之一) |
| P 实例 / D 实例 | 分别跑 Prefill / Decode |
| KV Cache Store | 官方 Motor 部署里"按需拉起"的组件 |
| LLM-DataDist | 大模型分布式集群与数据管理组件(CANN 侧) |
| HIXL | CANN 的单边通信库(ops 包里包含,见 A3/B1) |
附:D3 与 D4 的分工
| 问题 | 在哪一课 |
|---|---|
| Motor 五个子组件、部署形态、配置文件与端口规划 | D3 |
| Prefill/Decode 的本质差别、PD 分离的动机与官方优势、集群三要素、KV 传输的代价 | 本课(D4) |
| 起停、限流、主备倒换、伸缩、调优 | D5 |