LLM Serving 进入下半场:Prefill/Decode 解耦架构、KV 迁移与 PD 调度工程实践 很多人做大模型推理优化第一反应是量化、连续批处理、KV Cache、FlashAttention 或 Tensor Parallel。但线上服务真正跑到高并发、长上下文、多模型混部之后团队很快会遇到另一个问题为什么同一批 GPUPrefill 一上来Decode 延迟就开始抖为什么 TTFT 提升了TPOT 和 P99 却变差为什么压测 QPS 看起来很好真实用户体验反而更差。这些问题的背后往往不是单个算子不够快而是Prefill 和 Decode 两种负载被混在同一套资源池里彼此争抢显存带宽、算力时间片和调度机会。于是越来越多推理系统开始走向一个更“系统”的方向Prefill/Decode 解耦P/D Disaggregation。本文不从论文八股出发而是从工程视角系统拆解为什么 P/D 混部会互相伤害Prefill GPU 池和 Decode GPU 池应该怎么分KV Cache 跨池迁移到底贵不贵什么叫 Goodput为什么它比裸 QPS 更重要以及 vLLM、SGLang、TensorRT-LLM 语境下应该如何理解这类架构。读完之后你应该能把 P/D 解耦讲清楚也能把它和实际线上瓶颈、性能分析、调度设计、面试回答串起来。目录为什么说 LLM Serving 的瓶颈正在从“单点优化”走向“系统调度”先把问题看清Prefill 和 Decode 根本不是一类负载P/D 混部为什么会互相伤害什么是 Prefill/Decode 解耦架构为什么越来越多系统开始考虑 P/D 解耦P/D 解耦到底在优化什么最关键的代价KV Cache 迁移P 池和 D 池怎么配比不要靠拍脑袋Goodput 为什么比 QPS 更重要调度器怎么设计才像工程系统而不是 DemoP/D 解耦与 Continuous Batching、KV Cache、TP 的关系vLLM、SGLang、TensorRT-LLM 语境下怎么理解 P/D 架构什么时候适合上 P/D 解耦什么时候不适合性能分析怎么做别只盯着 tokens/s工程落地最容易踩的坑面试里如何把 P/D 解耦讲得像真正做过系统学习路线与实践建议总结1. 为什么说 LLM Serving 的瓶颈正在从“单点优化”走向“系统调度”早期很多团队做大模型推理业务规模还不大核心目标通常只有两个模型先跑起来单卡性能尽量压高这时候关注的重点很自然会落在模型权重量化Attention Kernel 优化Continuous BatchingKV Cache 管理Tensor Parallel 切分这些都很重要但它们大多属于“局部优化”。也就是说你是在优化某个算子、某种缓存、某个执行路径或者单个实例的吞吐。一旦系统进入真实线上阶段问题会开始变化短请求和长请求混在一起新请求不断进入同时老请求还在持续 decode一部分用户只要首 token 快另一部分用户更在意整体生成速度业务高峰时 admission control 开始触发GPU 利用率看起来不低但用户感知延迟越来越差这时你会发现系统瓶颈不再只是某个 kernel 不够快而是不同类型的请求和不同阶段的负载在错误地共享资源。P/D 解耦就是在这个阶段开始变得有价值。2. 先把问题看清Prefill 和 Decode 根本不是一类负载讨论 P/D 解耦之前最重要的是先承认一个事实Prefill 和 Decode 虽然都属于推理但它们的计算特性完全不同。2.1 Prefill 是什么Prefill 指的是把用户输入的 prompt 整段送进模型完成上下文编码并建立初始 KV Cache 的阶段。它的典型特征是一次要处理很多 token张量形状更大GEMM 更饱满并行性更强更容易吃满算力往往更偏 compute-bound通俗一点说Prefill 像是“整批大活一起干”适合把 GPU 算力榨满。2.2 Decode 是什么Decode 指的是模型进入自回归生成后一步一步生成 token 的阶段。它的典型特征是每一步只生成很少的新 token但要反复读取历史 KV Cache单步计算小、步数多对调度抖动非常敏感往往更偏 memory-bound通俗一点说Decode 像是“高频小单持续到来”重点不在单次算得多快而在于每一步都别被打断。2.3 一个最关键的工程结论Prefill 和 Decode 的矛盾不是“谁更重要”而是Prefill 喜欢大块时间片、喜欢大 batch、喜欢充分占用算力Decode 喜欢稳定、低抖动、持续拿到执行机会前者追求把机器跑满后者追求别被插队。这就天然埋下了冲突。3. P/D 混部为什么会互相伤害很多系统一开始采用的是混部思路同一组 GPU 既做 prefill也做 decode。这样实现最简单也最符合“资源共享最大化”的直觉。问题在于这种直觉在线上常常失效。3.1 Prefill 会打断 Decode 的稳定节奏Decode 的体验高度依赖于两个东西每一步生成的延迟是否稳定长尾是否可控如果系统突然插入一个较大的 prefill batch就可能出现当前 decode batch 被延后TPOT 抬升P95/P99 明显变差对用户来说这会体现为首 token 出得还行但后续输出一顿一顿的长回答尤其明显3.2 Decode 也会拖住 Prefill反过来Decode 虽然单步计算不大但它是持续存在的而且往往带着活跃 KV Cache、调度状态和流式输出责任。如果系统为了保住 decode 的延迟而频繁给它让路Prefill 也会出现队列等待变长TTFT 上升大 prompt 的进入变慢于是你会看到一种典型现象系统并不是绝对跑不动而是任何一侧一忙起来另一侧就开始恶化3.3 混部的本质问题P/D 混部最大的问题不是“实现不优雅”而是两种资源诉求完全不同的负载被迫在同一套 GPU 上竞争。竞争的对象包括计算时间片HBM 带宽KV Cache 容量调度优先级动态 batch 空间这就像把大货车和高频快递电动车放进同一条单车道理论上大家都能走实际上一旦流量上来整个系统就会抖。4. 什么是 Prefill/Decode 解耦架构P/D 解耦的核心思想其实不复杂既然 Prefill 和 Decode 的资源诉求不同那就不要让它们在同一池 GPU 上硬挤。于是系统被拆成两类资源池Prefill Pool专门负责处理新请求的 prompt 编码和初始 KV 构建Decode Pool专门负责接手已进入生成阶段的请求持续执行 token-by-token decode一个请求的大致生命周期会变成请求进入系统调度器把它送到 Prefill PoolPrefill 节点完成 prompt 计算产出初始 KV CacheKV Cache 或相关状态被迁移/转交到 Decode PoolDecode 节点继续负责后续生成这就是“解耦”。4.1 它不是简单的服务拆分很多人第一次听到会觉得这不就是把一个服务拆成两个服务吗不完全是。真正难的地方不是接口拆开而是两个池子的资源比怎么定请求何时切换阶段KV 怎么传传输时延是否吃掉收益两边负载波动时如何联动调度所以 P/D 解耦本质上是一种系统资源编排与调度架构不是普通的微服务拆分。5. 为什么越来越多系统开始考虑 P/D 解耦原因很现实随着模型更大、上下文更长、在线并发更高P/D 互扰越来越难靠小修小补解决。5.1 长上下文让 Prefill 更重上下文从 2k、4k 增长到 32k、64k 之后Prefill 的一次性计算量会明显抬升。这意味着单次 prefill 更容易形成“大活”对 decode 的打断更严重混部场景下抖动更大5.2 流式输出让 Decode 更敏感流式体验的核心不是平均值而是稳定性。如果 TPOT 的均值不错但 P99 经常抖用户依然会觉得“卡”。而 Decode 恰恰是最怕被打断的阶段。5.3 多业务、多模型混布让调度更复杂线上不只有一种请求短问答长摘要多轮对话工具调用RAG 拼接长 prompt这些请求的 prefill/decode 比例差异很大。如果还强行混在同一个资源池里调度复杂度会急剧上升。5.4 Goodput 比 Raw Throughput 更重要线上团队真正要保的是SLO 之内的 TTFTSLO 之内的 TPOT稳定的长尾延迟这时就不能只问“机器一秒能吐多少 token”而要问“在满足服务质量约束的前提下系统到底能稳定服务多少请求”P/D 解耦就是朝这个方向走的一步。6. P/D 解耦到底在优化什么很多人会误以为 P/D 解耦的目标是“提升绝对吞吐”。这不够准确。它真正优化的是下面几件事。6.1 降低阶段互扰这是最直接的收益。把 prefill 和 decode 分开后大 prompt 不会直接打断 decode 节奏decode 的 TPOT 更稳定长尾更容易收敛6.2 让不同 GPU 池各自做擅长的事Prefill Pool 可以倾向于大 batch更高算力利用更激进的请求聚合Decode Pool 可以倾向于更稳定的调度节奏更细粒度的步进控制更保守的 admission 策略这比一套统一策略硬覆盖两类负载更合理。6.3 提高 SLO 内有效吞吐解耦后系统未必在裸 QPS 上永远大幅领先但在满足 SLO 的前提下通常更容易保住TTFT 不爆TPOT 不抖P99 不飙这才是真正有业务价值的吞吐。6.4 让调优目标更清晰混部系统里你经常搞不清是 prefill 太重拖慢 decode还是 decode backlog 反过来堵住了新请求解耦后问题边界会更清楚Prefill 池看 TTFT、prefill queue、prefill batch utilizationDecode 池看 TPOT、decode backlog、active sequence 数系统更容易分析也更容易扩容。7. 最关键的代价KV Cache 迁移如果说 P/D 解耦最大的收益是“减少互扰”那最大的代价就是Prefill 做完之后如何把请求上下文安全、快速地交给 Decode 节点。这通常意味着 KV Cache 迁移或者等价的状态转移。7.1 为什么 KV 迁移这么关键因为 Prefill 的价值本质就是为后续 Decode 准备历史上下文。如果 Prefill 完成后 Decode 拿不到这些上下文就只能重新算一遍 prompt或者根本无法继续生成这显然不成立。所以 P/D 解耦不是算完就结束而是必须解决“算完以后怎么交棒”。7.2 KV 迁移的主要成本KV 迁移的成本主要体现在额外网络传输节点间状态同步迁移过程中的排队与等待可能的内存拷贝开销如果 prompt 很长初始 KV 很大迁移成本就会明显上升。7.3 一个核心权衡P/D 解耦是否值得常常取决于下面这个判断“P/D 混部造成的长期互扰损失是否大于一次 KV 迁移引入的额外成本”如果答案是是那么解耦值得考虑。7.4 什么场景下迁移成本更容易接受以下场景更容易从 P/D 解耦里获益prompt 较长prefill 本身足够重decode 生命周期长后续收益能摊薄一次迁移开销集群内有较高带宽互联系统对 TPOT 稳定性要求高反过来如果请求极短、生成极短、上下文也不长那么多引入一次迁移未必划算。8. P 池和 D 池怎么配比不要靠拍脑袋P/D 解耦落地后工程上第一个大问题就是Prefill Pool 和 Decode Pool 各放多少 GPU这是很多团队最容易拍脑袋的地方。8.1 先明确两个池子的负载来源Prefill Pool 的压力主要来自新请求到达率平均 prompt 长度长 prompt 比例Decode Pool 的压力主要来自活跃会话数平均输出长度持续生成时长TPOT 目标这两边本来就不一定同比例增长。8.2 一个直观判断框架可以先用下面的思路做一版粗估P 池容量 ~ 新请求速率 × 平均 prefill 成本 D 池容量 ~ 活跃会话数 × 平均 decode 成本这里的“成本”不能只看 FLOPs还要看单阶段平均耗时显存占用队列等待SLO 约束8.3 业务变化会直接改变最优配比例如RAG 场景 prompt 很长P 池要更厚聊天场景生成很长D 池要更厚夜间批量摘要任务可能 P 池压力更大客服对话场景常常 D 池更敏感所以 P:D 配比不是固定常数而是业务相关参数。8.4 更像工程师的做法真正靠谱的方式不是猜而是统计真实请求分布prompt 长度、输出长度、并发模式分别测 prefill 单阶段成本和 decode 单步成本结合目标 SLO 做容量测算在压测中观察哪一池先形成 backlog动态调参或弹性扩缩也就是说P/D 解耦不是“拆完就赢”而是把资源配置问题显式化了。9. Goodput 为什么比 QPS 更重要这是理解 P/D 解耦价值的关键概念之一。9.1 裸 QPS 的误导性很多压测报告喜欢展示QPS总 tokens/sGPU 利用率这些指标当然有用但它们无法直接回答一个业务问题这些请求里有多少是在用户可接受延迟内完成的如果系统虽然吞吐很高但TTFT 超标TPOT 长尾超标请求频繁超时那这些吞吐并不真正有价值。9.2 Goodput 的直觉Goodput 可以简单理解为满足既定 SLO 约束的有效吞吐。比如TTFT 必须小于某阈值TPOT P95 必须小于某阈值成功完成率必须足够高只有满足这些条件的请求才算“有效服务”。9.3 P/D 解耦为什么天然更适合做 Goodput 优化因为它把两类矛盾负载拆开后更容易分别守住Prefill 的首 token 时延Decode 的生成稳定性这意味着系统虽然可能增加了一次迁移但却更容易把“有效请求数”做上去。从工程角度看这往往比只追裸吞吐更值钱。10. 调度器怎么设计才像工程系统而不是 DemoP/D 解耦的成败很大程度上不在模型而在调度器。10.1 调度器至少要回答的四个问题新请求先进哪个 Prefill 节点Prefill 完成后转发到哪个 Decode 节点当前 Decode 池是否还接得住新的活跃会话哪一侧出现拥塞时系统如何退化而不是雪崩10.2 只看最空闲节点是不够的很多人会下意识做一个“最少负载优先”。这在线上往往太粗糙因为真实负载不是一个数字能概括的。你至少还要看当前队列长度预计 KV 占用活跃序列数当前 batch 结构TP group 可用性节点间网络距离所以调度器更像是一个多目标优化器而不是简单的 round-robin。10.3 Decode 池调度尤其要避免“假空闲”有些节点当前看起来 QPS 不高但已经挂着很多长会话和大量 KV Cache。如果继续把新请求导进去结果通常是admission 没有立刻失败但后续 TPOT 和 P99 快速恶化所以 Decode 池的容量评估不能只看当前 token 速率还要看“未来一段时间的持续压力”。10.4 需要退化策略成熟系统不能只有理想路径还要有退化策略例如Decode 池拥塞时限制长 prompt 进入Prefill 池排队过长时做 admission control部分请求回落到混部池对不同优先级业务做差异化限流这部分能力比单纯把架构图画漂亮更重要。11. P/D 解耦与 Continuous Batching、KV Cache、TP 的关系P/D 解耦不是替代这些技术而是和它们形成新的组合关系。11.1 和 Continuous Batching 的关系Continuous Batching 解决的是请求到达时间不一致时如何动态拼 batch如何减少 GPU 空转P/D 解耦解决的是prefill 和 decode 是否应该共享同一执行池前者更偏执行策略后者更偏资源架构。两者不是二选一反而常常一起出现。11.2 和 KV Cache 的关系KV Cache 是 Decode 阶段的核心状态资产。P/D 解耦后KV 管理问题变得更复杂因为你不仅要考虑分配复用回收还要考虑节点间迁移迁移后的布局一致性P 池和 D 池对 KV 生命周期的协同所以 P/D 解耦不是弱化 KV 问题而是把 KV 问题升级成了“跨池状态管理”问题。11.3 和 Tensor Parallel 的关系如果模型本身需要 TP那么 P 池和 D 池内部也可能各自有 TP group。这会带来更多现实约束Prefill TP group 和 Decode TP group 是否同规模KV 迁移是单卡到单卡还是 group 到 group不同池子的拓扑是否一致跨机 TP 下解耦是否更贵所以 P/D 解耦一旦叠加 TP调度复杂度会明显增加。12. vLLM、SGLang、TensorRT-LLM 语境下怎么理解 P/D 架构很多人容易把“某框架支持某特性”理解成“系统问题已经被自动解决”。这要谨慎。12.1 vLLM 语境vLLM 强项在于PagedAttention高效 KV 管理Continuous Batching较成熟的 serving 执行模型在这个语境下理解 P/D 解耦时要重点思考的是当前实例更偏混部还是可拆池KV block 管理和跨节点迁移如何结合调度器如何感知活跃序列与 block 使用率12.2 SGLang 语境SGLang 讨论更多的是请求执行图前缀复用调度表达能力推理服务编排在这个语境下P/D 解耦更容易与Prefix Cache复杂请求编排多阶段执行控制联系起来理解。12.3 TensorRT-LLM 语境TensorRT-LLM 更强调图优化kernel 性能高效 runtime生产级推理路径在这个语境下讨论 P/D 解耦重点就会转向两个池子内部的单实例性能是否足够好跨池切换是否抵消了 engine 优化收益不同 engine 配置是否分别适配 prefill 和 decode12.4 一个统一视角无论是哪种框架P/D 解耦都不是一个“自动开关”。它始终对应同一个系统问题是否要把两类不同负载拆到不同资源池并为此承担额外状态迁移和调度复杂度。框架只决定你更容易怎么实现不决定这个问题本身是否存在。13. 什么时候适合上 P/D 解耦什么时候不适合这件事很容易被讲成“先进架构”但工程上不能迷信它。13.1 更适合的场景长上下文请求较多流式输出体验很重要并发高P99 压力明显Prefill 和 Decode 干扰已经在压测中可见集群网络较好能承受 KV 迁移系统已经有较成熟的调度和监控体系13.2 不一定适合的场景请求很短prompt 和输出都不长业务规模小混部还远未到瓶颈集群网络一般跨池迁移代价大团队没有足够的调度与观测能力当前单实例瓶颈还没有解决13.3 一个务实结论如果你现在连TTFT 和 TPOT 的分阶段指标KV 占用batch 结构decode backlog都还没有监控清楚那大概率还没到“先上 P/D 解耦”的时候。先把系统看清再决定要不要拆。14. 性能分析怎么做别只盯着 tokens/s做 P/D 解耦评估最忌讳的是只看一个总吞吐数字。14.1 至少要分阶段看你至少要拆开看Prefill latencyTTFTTPOTDecode P95/P99请求完成率GoodputKV 迁移耗时Prefill/Decode 两池 backlog14.2 要看阶段互扰是否真的下降不是说拆成两个池子就算成功而是要验证大 prompt 到来时decode TPOT 是否更稳定decode 池的长尾是否明显改善prefill 池是否因为排队而把 TTFT 抬太高14.3 要做真实负载而不是玩具负载很多压测脚本的问题在于prompt 长度固定输出长度固定请求间隔均匀这种负载很难看出 P/D 解耦的真实价值。更好的做法是模拟长短 prompt 混合长短输出混合峰值突发流式会话持续驻留因为真实线上就是这样。14.4 还要看迁移成本是否吞掉收益如果你发现decode 的抖动确实下降了但 TTFT 因为迁移和排队上升太多那么架构不一定真正更优。这也是为什么 P/D 解耦必须用端到端指标来评估而不是只看局部性能。15. 工程落地最容易踩的坑15.1 误把“拆服务”当成“做解耦”只把 API 分成两个服务不等于系统真的解耦了。如果还是共用同一组 GPU还是共用同一套队列还是没有独立容量控制那只是代码拆分不是资源解耦。15.2 没有算清 KV 迁移成本很多方案 PPT 上很好看问题都出在这一步prompt 长时 KV 太大网络没那么快迁移过程引入额外等待最后收益被吞掉。15.3 没有给两池做独立监控如果上线后你仍然只看一个总体 QPS 和一个总体延迟那定位会非常痛苦。P 池和 D 池必须至少分开观测队列长度活跃请求GPU 利用率显存占用迁移耗时admission reject15.4 资源配比静态写死业务分布会变白天夜间会变长短请求比例会变。如果你把 P:D 比例固定死很可能在某些时段效果好某些时段反而更差。15.5 忽略异常路径例如Prefill 成功但迁移失败怎么办Decode 池节点故障怎么办请求中途取消如何回收状态P 池热点和 D 池热点如何迁移这些异常路径决定它是不是一个生产系统。16. 面试里如何把 P/D 解耦讲得像真正做过系统很多候选人一说这个主题就容易停在概念层Prefill 是算 promptDecode 是生成 token两者分开更高效这远远不够。更像做过系统的表达方式应该是16.1 先讲问题不先讲方案可以先说“线上混部时Prefill 更偏 compute-heavyDecode 更偏 memory-bound 和 latency-sensitive。大 prompt 或批量 prefill 进入后容易打断 decode 节奏导致 TPOT 和 P99 恶化。所以我们会考虑把两个阶段拆到不同 GPU 池减少互扰。”这样一开口就体现你理解的是系统矛盾而不是名词解释。16.2 再讲收益但别讲成银弹可以继续说“解耦的直接收益通常不是绝对 tokens/s 最大化而是提高 SLO 内的有效吞吐也就是 Goodput。Decode 更稳定长尾更可控但代价是要承担 KV 迁移和更复杂的调度。”这比只说“性能更好”强得多。16.3 最后讲代价和边界例如请求太短时收益未必覆盖迁移成本网络拓扑差时很容易被传输拖死如果当前系统连阶段指标都没打清楚贸然做解耦风险很高这类边界表达最能拉开和“只背过概念”的差距。17. 学习路线与实践建议如果你想把这个主题真正学扎实可以按下面的顺序推进。17.1 先补清推理基础先彻底理解Prefill / Decode 区别KV Cache 生命周期Continuous BatchingTTFT / TPOT / Throughput / P9917.2 再补系统调度视角重点理解为什么不同请求会互相干扰为什么队列论和容量规划重要为什么在线系统要看 Goodput17.3 再结合框架读实现建议从以下方向看vLLM 的请求调度和 KV 管理SGLang 的执行模型与缓存复用TensorRT-LLM 的 runtime 与 engine 优化思路17.4 自己做一个小实验哪怕没有完整集群也可以先做一个简化实验构造短 prompt 长 prompt 混合负载比较混部执行与拆阶段执行的 TTFT / TPOT / P99观察某一侧压力升高时另一侧是否被拖累记录在不同负载分布下的最优资源配比变化你不一定非得把完整解耦系统实现出来但至少要把它的收益和代价量化出来。18. 总结P/D 解耦不是一个“看起来高级”的架构名词它本质上是在回答一个非常现实的问题当 Prefill 和 Decode 的负载特性已经明显不同并且它们在同一套资源上互相伤害时系统是否应该为减少互扰而付出额外迁移和调度成本。它的核心价值不在于把架构图拆成两块而在于让 Prefill 和 Decode 各自在更合适的资源池里运行降低阶段互扰提高 SLO 内有效吞吐让调度、扩容和性能定位更清晰它的核心代价则在于KV Cache 迁移资源池配比更复杂的调度器更高的观测与运维要求所以真正成熟的工程判断从来不是“P/D 解耦先进不先进”而是你的业务负载、网络条件、模型规模和服务目标是否已经到了值得做这件事的阶段。如果你能把这个问题讲清楚无论是做推理系统设计、性能优化、架构评审还是准备 AI Infra / LLM Serving 面试这个主题都会很有分量。