资讯动态

PD解耦:物理隔离prefill与decode,首字延迟骤降80%的架构实战

发布时间:2026/10/13 8:13:56 来源:尧图企业网站定制
这两年做大模型推理优化绕不开一个现象GPU越堆越多单卡算力越来越强但一碰到高并发首字延迟还是像过山车一样忽上忽下。问题往往不在模型本身而在 prefill 和 decode 被强行塞进了同一张卡。DistServe 提出的 PD 解耦思路直接把这两个阶段放到不同物理 GPU 上用物理隔离把算力干扰彻底切断行业内很多实测场景里首字延迟能骤降 80%。这篇文章我就从架构拆解、落地实操和踩坑排查三个角度把这个“里程碑架构”讲明白。无论你是搞推理服务的人还是做大模型应用但总被响应延迟困扰的开发者这套思路都值得认真看一遍。它不只是一篇论文里的概念而是已经被验证过能解决真实线上问题的架构范式。1. PD 解耦为什么是当前大模型推理的必经之路1.1 传统“prefilldecode 同一张卡”的算力浪费先看一个最简单的推理场景请求进来GPU 要先把 prompt 里所有 token 过一遍生成完整的 KV cache这个过程叫 prefill。接下来模型拿着 KV cache 逐 token 往外吐结果每吐一个 token 都要把所有权重和 KV cache 从显存里过一遍这个过程叫 decode。prefill 的典型特征是“计算密集型”。一个 4096 token 的 promptGPU 需要在很短时间里做大量矩阵乘法计算并行度很高会把 GPU 的算力瞬间吃满。decode 的典型特征是“访存密集型”。每次只生成一个 token计算量不大但要把模型参数和 KV cache 从 HBM 搬到计算单元瓶颈在显存带宽不在算力。这两类任务放进同一张卡会出现什么情况当一批长 prompt 请求同时进来prefill 把算力占得死死的后面那些正在流式输出的 decode 请求就只能排队等着。反过来如果 decode 请求占了大量显存带宽prefill 要做的计算也会被拖慢。餐厅的例子很贴切同一间厨房炒菜师傅和传菜员共用灶台和通道。炒菜时火焰和大锅都被占住传菜员只能站在旁边等传菜员频繁进出时炒菜师傅也会被挤得施展不开。你加再多的服务员只要厨房还是同一间问题就依然存在。1.2 DistServe 的物理隔离思路让 prefill 和 decode 各干各的DistServe 的核心变化是把 prefill 和 decode 从“同一张卡”变成“两张独立的卡”。系统部署时一组 GPU 专门负责 prefill称为 prefill 池另一组 GPU 专门负责 decode称为 decode 池。请求先进入 prefill 池把完整 prompt 过一遍生成 KV cacheKV cache 通过高速数据传输通道送到 decode 池decode 池拿到 KV cache 后只做逐 token 生成。这么做的好处非常直接。prefill 卡上全是 prefill 任务可以放心把 batch 调大让 GPU 算力充分跑满不会被流式请求打断。decode 卡上全是 decode 任务显存带宽被解码请求独占不用担心某个大 prompt 的 prefill 突然冲进来抢资源。两边的吞吐能力也可以独立扩展prompt 太长导致 prefill 压力大就加 prefill 卡线上并发输出量大就加 decode 卡。这就是标题里“物理隔离彻底打破算力干扰”的含义。不是靠优先级调度去“尽量少干扰”而是从资源层面直接让两个阶段不再共享同一个 GPU把干扰的根源切掉。1.3 80% 首字延迟下降到底怎么来的首字延迟也就是 TTFT是用户发出请求到模型返回第一个 token 的时间。在传统架构里TTFT 可以拆成四段排队时间请求在推理服务里等可用显存的时间prefill 计算时间GPU 把 prompt 完整过一遍的时间KV cache 传输时间数据在不同处理单元之间搬运的时间decode 首 token 时间拿到 KV cache 后生成第一个输出 token 的时间在混合部署模式下最不确定的是“排队时间”和“prefill 计算时间”。一批长 prompt 请求进来prefill 要跑好几秒后面那些请求只能干等。即便你的模型单次推理很快一旦发生波次叠加TTFT 就会变成灾难。PD 解耦之后prefill 池只处理 prefill 任务可以把多个请求拼成大 batch 一起算单位时间内能消化更多 prompt。decode 池不再需要等待 prefill 完成只要 KV cache 到位立刻就能开始生成。于是排队时间几乎被清掉prefill 计算时间也因为专用化而大幅缩短。在一些高并发长 prompt 的实测场景里TTFT 从五六秒压到一秒出头确实能达到 80% 的降幅。但这句话要正确理解80% 不是对每个请求都成立的承诺。短 prompt、低并发场景下prefill 本来就只有几十毫秒此时反而要多付出一次 KV cache 传输的开销收益不一定明显。后面实操部分我会详细展开这一点。2. 拆开架构看门道DistServe 如何做到 PD 解耦2.1 整体拓扑两个独立计算池加一条 KV 高速通道一个大致的生产拓扑长这样网关层接收外部请求识别请求是否已经完成 prefill决定路由到哪个池prefill 池负责处理新 prompt生成 KV cache将 KV cache 切分并发送出去decode 池负责从远端接收 KV cache缓存到本地显存随后执行流式生成KV transfer 服务负责块级传输、预取、压缩和错误重传数据流大概是用户请求到网关网关把没有 KV cache 的请求分给 prefill 节点。prefill 节点处理完 prompt 后把成果包装成若干个 KV cache 块通过专用通道发给 decode 节点。decode 节点收到块后按位置存好然后开始逐 token 生成。输出 token 再经网关返回给用户。这里有一个非常容易被低估的组件KV cache 传输通道。要知道一个 4096 token 的 prompt对应的 KV cache 可能达到几百 MB如果 batch 大一点单次传输的数据量能到 GB 级别。如果 KV cache 传输速度跟不上prefill 做得再快也是白搭。所以真实实现里通常要借助 RDMA 这类高速网络并且按块粒度、异步预取、流水线传输而不是等全部 prefill 算完再一次性搬过去。打个比方prefill 相当于把一整块料切好装盘decode 相当于按顺序上菜。如果要求“全部切好以后才能开始传”后厨就会积压如果一边切一边往传菜口送decode 那边就能提前开工。2.2 调度策略从一刀切队列到分池子调度传统推理框架普遍使用一个全局队列请求按到达顺序排队。同一个 worker 既要执行 prefill也要执行 decode调度器只能不断在两类任务之间切换相当于在厨房里同时给多个订单炒菜和传菜总是在抢资源。PD 解耦后调度逻辑必须跟着改。DistServe 的做法是prefill 侧和 decode 侧分别维护独立的队列。prefill 队列只放“需要生成 KV cache”的请求调度器按最大 batch 优先策略把多个请求拼成一个 batch因为 prefill 阶段最适合做大 batch 并行。decode 队列只放“已经拥有 KV cache”的请求调度器按连续批处理策略做流式生成让已开始的请求以低延迟持续输出。网关还要做一次关键判断请求是否已经有 KV cache。如果没有走 prefill如果有走 decode。这个判断逻辑不复杂复杂的是两个池之间的水位控制。如果 prefill 池处理速度太快decode 池消费不过来KV cache 就会积压在传输通道或 decode 本地缓存里白白占用显存。如果 prefill 池处理太慢decode 池长期空转GPU 利用率又会很难看。所以生产环境一定要加“水位线”当 decode 侧待处理 KV cache 数量高于阈值时让 prefill 侧适当放慢当 decode 侧队列见底时提高 prefill 侧并发。2.3 为什么物理隔离比逻辑隔离更能“打破算力干扰”有人会问我用容器、cgroup、进程优先级把一个 GPU 上的 prefill 任务和 decode 任务分类并限制它们的资源配额是不是也算隔离算但远不够。逻辑隔离解决的是“调度权”问题物理隔离解决的是“资源独占权”问题。同一个 GPU 里的计算单元、一级缓存、二级缓存、显存带宽本质上是共享的。即使你把 prefill 进程绑到了某个计算实例上decode 进程在内存带宽压力大时依然会被拖慢。反过来prefill 突发计算时也会抢占供电和散热余量导致 decode 的时钟频率波动。物理隔离则是把 prefill 和 decode 放到完全不同的物理 GPU 上两者不再共享任何执行部件和显存带宽。prefill 再狂暴也只会影响它自己的那张卡decode 节点永远拿到完整的内存带宽预算。这就是为什么 DistServe 要强调“物理隔离”而不是在同一个设备上做软隔离。代价也很明显资源复用率下降还要增加一条 KV cache 传输链路。但在高并发、长 prompt、流式输出要求高的场景用一点资源冗余换首字延迟的大幅下降完全值得。3. 落地实操从零搭建一个 PD 解耦推理服务3.1 实验拓扑两卡起步先跑通最关键的数据通道第一次尝试 PD 解耦不一定要搭一个大集群。准备两张 GPU 卡就能做一个最小验证。如果只有一台双卡服务器也可以做实验。虽然两块卡共用 CPU 和 PCIe 总线但 GPU 核心、显存、显存带宽都是物理独立的已经符合物理隔离的要求。好处是调试方便坏处是测不到跨机网络的真实开销。如果有条件建议用两台机器各放一张卡通过高速网卡互联这样更接近生产环境。我建议的最小拓扑是这样的节点 Aprefill 服务绑定 GPU 0监听 prefill 端口节点 Bdecode 服务绑定 GPU 1监听 decode 端口网关路由请求维护 KV cache 元信息KV cache 传输服务负责把节点 A 生成的 KV cache 推到节点 B实验的第一步不是调模型而是先跑通 KV cache 传输。可以构造一个非常短的 prompt在节点 A 完成 prefill 后立即把 KV cache 推给节点 B再在节点 B 上继续生成。这一步没有跑通后面所有指标都没意义。3.2 关键配置与部署步骤以常见的 PD 解耦推理框架为例核心步骤如下第一步在 prefill 节点加载模型开启 KV cache 导出模式。这一步通常是在 model 配置里增加一个开关标明该节点只做 prefill并把生成的 KV cache 写入传输缓冲区。第二步在 decode 节点加载同一个模型并配置远端 KV cache 接收器。注意模型权重必须保持一致否则 KV cache 结构对不上。第三步配置网关后端地址。网关需要知道哪些请求路由到 prefill、哪些路由到 decode。简单做法是在请求头里增加一个“是否已生成 KV cache”的标记网关根据标记转发。第四步调整 KV cache 传输粒度。一个比较稳妥的起点是把每块大小设为 64 个 token 对应的 KV cache。块太大传输延迟高块太小传输次数多控制面开销大。第五步设置水位线相关参数。比如 prefill 队列最大积压长度、decode 侧消费阈值。生产环境一般会做成动态调整但实验阶段可以先固定经验值。部署完成后先做一次端到端冒烟测试发一个长 prompt确认节点 A 完成 prefill、KV cache 到达节点 B、节点 B 能继续正常生成 token。如果这一步通了再开始压测。3.3 压测指标选择如何验证首字延迟下降了 80%压测最忌讳只看一个数字。我自己通常准备四类指标TTFT请求发出到返回第一个 token 的时间TPOT每个 token 的平均输出时间端到端吞吐单位时间完成的请求数GPU 利用率prefill 池和 decode 池分别观察测试时准备 128、1024、4096 token 三档 prompt 长度并发数从 1 到 32 慢慢加压。示例结果可以这样记录并发数prompt 长度传统架构 TTFTPD 解耦 TTFT降幅810241800 ms420 ms77%840965200 ms950 ms82%3240968600 ms1550 ms82%112890 ms140 ms-56%注意最后一行短 prompt 低并发时PD 解耦反而更慢因为多了一次 KV cache 传输。这个现象非常正常不代表方案有问题而是说明要分场景使用。压测时还要做一件事单独记录 KV cache 传输耗时。如果发现 TTFT 里 KV 传输占了三分之一以上说明网络侧还没调好后面排查部分会讲到。4. 掉坑记录PD 解耦系统最常见的 4 个问题4.1 KV cache 传输成为新的长尾瓶颈第一个容易踩的坑是 KV cache 传输链路变成了新瓶颈。典型症状prefill 节点 GPU 利用率很高decode 节点 GPU 利用率却很低两端之间的网络传输队列拥堵。排查时先看 KV cache 平均传输耗时再看是否因为“同步传输”导致等包延迟。我在实验时碰到过一次很典型的情况prefill 端要等整段 prompt 全部处理完才一次性发送 KV cachedecode 端干等着。后来改成边生成边传输以 64 token 为单位把 KV cache 切块decode 端收到第一块就能开始处理TTFT 又降了一截。这个问题的排查要点是不要只关注 KV cache 总量要看首块到达时间。如果 KV cache 要全部生成完才能发总传输时间就成了 TTFT 的一部分而且是不可忽略的一部分。4.2 prefill 和 decode 负载失衡第二个高频问题是两端负载失衡。现象有两种prefill 队列堆积decode 节点空转或者 decode 队列堆满prefill 节点不再接收新请求。原因通常出在水位线设置上。假设一个 prefill 节点每秒能处理 40000 token 的 prompt一个 decode 节点每秒能生成 8000 token。如果请求平均 prompt 长度是 2000 token输出长度是 800 token那么一个请求需要 prefill 端消耗 2000 个 token 的算力decode 端消耗 800 个 token 的生成能力。流量达到一定规模后两端需要的节点数比例大约等于 8000 个 decode token 对应 40000 个 prefill token也就是一个 decode 节点需要五个 prefill 节点才能喂饱。实际负载不会这么稳定所以更好的做法是让网关动态感知两端队列长度。当 decode 队列变长时让 prefill 端降低 batch 大小或暂缓接入新请求当 decode 队列快空了再放开 prefill 端并发。4.3 decode 节点显存爆炸第三个问题是 decode 节点的显存压力。prefill 阶段生成 KV cache 后生命周期很短计算完就能释放。但 decode 阶段不同一个长输出请求可能会持续生成几千个 tokenKV cache 要在 decode 节点驻留很久。如果线上同时跑很多长输出请求decode 节点的显存很快就不够用了。解决办法一般有三个方向在 decode 节点启用分页 KV cache避免显存碎片限制最大并发输出请求数做一个显存预算对空闲超时的请求做换出释放显存给活跃请求注意不要在 decode 节点上沿用 prefill 节点的显存估算方式。两个阶段对显存的需求模型完全不同一定要分开评估。4.4 小请求场景优化空间有限第四个问题不是 bug而是场景适用性。如果业务以几百 token 的短 prompt 为主PD 解耦的效果确实不明显。因为 prefill 本来只需要几十毫秒KV cache 也很小传输开销可能比 prefill 本身还高。此时强行拆开TTFT 不仅不降反而会升。更务实的做法是混合部署网关根据 prompt 长度做决策短 prompt 走传统合池路线长 prompt 走 PD 解耦路线。这样既保住了普通小请求的低延迟又解决长请求拖垮整个集群的问题。DistServe 这类架构的价值在于给了调度系统一个更细粒度的手段而不是让你把所有流量无脑切过去。我个人在实际测试里的体会是PD 解耦最大的贡献不是某一个指标数字而是让 prefill 和 decode 各自拥有了独立调优的空间。80% 的首字延迟下降听上去很吓人但它需要正确的负载模型、恰当的 KV 传输配置和稳定的水位控制才能复现。如果你正准备做类似改造我建议先从两张卡开始把 KV cache 传输延迟和两端队列水位监控做起来再判断是否全面推广。这套架构确实是里程碑式的但里程碑不是终点而是让后续优化有了更清晰的起点。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑