PD分离+弹性伸缩/角色切换的实践笔记

PD分离+弹性伸缩/角色切换的实践笔记

本文作者:kaiyuan
PD分离+弹性伸缩/角色切换的实践笔记

想深耕AI Infra领域?欢迎访问InfraTech库!内容涵盖大模型基础、PyTorch/vLLM/SGLang框架入门、性能加速等核心方向,配套50+知识干货及适合初学者的notebook练习:https://github.com/CalvinXKY/InfraTech

PD(Prefill-Decode)分离是推理侧提升性能的主流手段之一:从2024年兴起、2025年逐步普及,如今已成为常见部署选项;与之相伴的EPD(Encode-Prefill-Decode)分离、AFD(Attention-FFN Disaggregation)[1]、Chunked Prefill、分布式KV cache等,也把推理服务的工程复杂度整体抬高了一档。长期实践表明,在大规模集群里,单一PD分离并不总是全局最优,很难用固定形态覆盖波动的流量与多变的需求。本文结合工程经验,介绍两类用于弥补PD分离局限的手段:弹性伸缩角色切换

1 为什么需要PD分离

在PD分离普及之前,GPU上多为混合部署:同一请求的Prefill与Decode在同一批GPU上完成。模型参数变大后,矛盾会凸显,例如:算力给少了,Prefill阶段时延拉长(TTFT偏大);算力给多了,Decode阶段又容易出现算力闲置。


PD分离依据Prefill(偏算力密集)与Decode(偏访存密集)的差异,把资源更精细地切分到两阶段,以提升整体利用率。

vLLM的PD分离示意图

PD分离自提出以来常被质疑,认为其徒增系统复杂度、得不偿失,但从vLLM/SGLang、Dynamo(NVIDIA)等主流推理框架的演进看,各方都在积极适配这一方向。2025年初,笔者曾围绕该方向做过一些梳理(如《vLLM PD分离方案浅析》、《vLLM PD分离KV cache传递机制详解与演进分析 》等),虽以vLLM为主,也顺带涉及其它框架;目前各框架对PD分离的支持已趋于稳定,业界仍不断出现新的工程解法。

  • 融入K8S生态的llm-d(最新版本v0.5)[2]

v0.5 版本新增了可复现基准测试工作流、分层 KV 卸载、缓存感知 LoRA 路由、双活高可用架构、基于 UCCL 的传输容错,以及缩容至零的自动扩缩容能力;经验证,单张 B200 推理 GPU(宽模式专家并行)解码吞吐约 3.1k token/s,在 16×16 B200 预填充 / 推理拓扑下最高输出 50k token/s,与轮询基线相比首词时延(TTFT)实现数量级降低。

  • 字节推出的aibrix(已融入vllm生态)[3]

AIBrix 提供一套云原生解决方案,专为企业需求定制,针对大语言模型(LLM)推理的部署、管理与弹性扩缩进行了深度优化。

  • Ray Serve LLM(ray原生解决方案)[4]

Ray Serve LLM提供一套高性能、可扩展的框架,用于在生产环境中部署大语言模型(LLM)。它针对分布式大语言模型推理服务场景,对Ray Serve基础组件做了专项优化,兼具企业级特性与OpenAI API兼容能力。可结合vLLM框架实现PD分离功能。

  • NVIDIA Dynamo[5]

随着模型规模不断增大,并越来越多地融入需要多个模型协同的 AI 工作流中,在规模化部署时,必须将这些模型分布到多台节点上,并在 GPU 之间进行精细协调。随着采用诸如解耦式推理(disaggregated serving)等推理优化方法,这种复杂性进一步提升——推理的不同阶段被拆分到不同 GPU 上执行,响应在多块 GPU 间拆分与聚合,给协同调度和数据传输都带来了更多挑战。


概括而言,PD分离的核心是在约束TTFT/TPOT/ITL与集群吞吐(如QPS)的前提下,优化GPU资源的阶段化分配;在许多场景下效果确实明显。但若只保留一种静态部署形态去应对所有负载,有时不但省不下资源,反而可能拉高总消耗。这也是下文要讨论弹性伸缩与角色切换的原因。

Case1:大参数量与稀疏结构下的波动

当前主流LLM里,MoE等稀疏结构很常见;在PD分离形态下,资源利用率往往波动更大。为拉高Decode吞吐,常见做法是跨机EP等扩展方式,但其隐含前提是基线流量足够。当流量回落时,仍可能出现部分GPU利用率不足。


此外,单实例若固定占用多台机器,规模一旦按参数敲定,中途弹性扩缩容会变得困难,与流量起伏的匹配度下降。

Case2:场景的快速变化

智能体类客户增多后,流量往往不再只是单一模型、单一曲线,而是多模型、多形态叠加。这要求推理集群能适配多模型的波动;对单模型的PD分离部署而言,往往既需要实例级扩缩,也需要实例内部(如P/D子池或机器数)的细粒度调整,才能跟上场景变化。

下文介绍我们团队在应对上述问题时探索过的两个方向。

2 弹性伸缩

对多数云厂商而言,整条P/D实例的扩缩已是基线能力,但粒度通常停在单个实例层面。要进一步提效,需要更细的弹性。

vLLM RoadMap 2025 Q3[6]中相关能力规划:


笔者团队当时在NPU硬件上基于KV pool展开实践。并据此提交过RFC[7]

在分离式P/D(Prefill/Decode)场景中,支持P/D实例的弹性伸缩是大规模推理部署的关键需求,正如vLLM 2025 年Q3 路线图“Autoscaling P & D Replicas”中所提到的。这一功能不仅能提高资源利用率,还能提供容错支持。尤其是在Ascend超节点上,实例通常跨多个设备部署,重建实例可能产生较大影响,因此该能力尤为重要。

借助Mooncake Store和Mem Cache等分布式KV Cache功能的支持,我们可以以此为基础实现P/D实例的弹性伸缩。在伸缩实例时,需要管理三种类型的连接:

a. P 与 D 之间的 D2D 链接,由 connector 及其他组件建立;
b. P/D 与 KV Pool 之间的链接;
c. P/D 与 scheduler 之间的链接。

这涉及实例注册、链接断开/建立、链接重建等流程。

方案架构图

实施计划:

阶段1 同构伸缩(Homogeneous Scaling)
1.1 P-instance 伸缩的实现
1.2 D-node 伸缩的实现

阶段2 异构伸缩(Heterogeneous Scaling)
2.1 异构 KV cache 传输的支持
2.2 P/D 配置下异构传输的支持

实践效果(工程侧):因前期已对KV Pool做了较完整适配,传输建链、KV cache生命周期等重复建设相对较少;难点在于异构伸缩下的并行策略与多模型配比,往往需要实验得到先验。在部分场景下,吞吐可提升约5%~15%。部分实现已以PR形式贡献至vLLM社区(5822[8]、5063[9]),可供对照参考。

3 角色切换

角色切换指在不长时间停机的前提下,快速改变实例承担的角色。实践中可归纳为几类能力:

  • P与D的角色热切换
  • 实例的动态热加载(多模型间切换);
  • PD分离与混合部署之间的热切换。

a> P与D角色热切换
一般在P、D硬件规格一致时更易落地。例如同一模型下P实例不足、D实例有余,可将部分D实例切为P(反之亦然)。过程中需关注Prefix cache等一致性;借助分布式KV cache可降低工程复杂度。

b> 实例动态热加载
在不同模型间快速切换,例如同一P实例从模型A切到模型B;常见会结合休眠/睡眠类机制减少冷启动成本(具体依框架与硬件而定)。

vLLM中通过睡眠模式(sleep mode)[10]目前设置了两个等级:

  • level 1
  • 操作:卸载模型权重并清除KV cache。
  • 内存:模型权重被移动到CPU内存;KV cache被清除。

  • level 2
  • 操作:同时丢弃模型权重和KV缓存。
  • 内存:模型权重和KV cache都被清除。

应用中一般使用level2模式。调用示例:

# Sleep level 2# Put the engine to sleep (level=2: discard both weights and KV cache)llm.sleep(level=2)# Reallocate weights memory onlyllm.wake_up(tags=["weights"])# Load weights in-placellm.collective_rpc("reload_weights")# Reallocate KV cachellm.wake_up(tags=["kv_cache"])

过程步骤示意如下:


在sleep和wake_up操作中,会分别调用unmap_and_release(handle)与create_and_map(handle)函数,这两个函数定义于vllm/csrc/cumem_allocator.cpp中。

//代码节选 void create_and_map(unsignedlonglongdevice,ssize_t size,CUdeviceptr d_mem,#ifndef USE_ROCMCUmemGenericAllocationHandle*p_memHandle){#elseCUmemGenericAllocationHandle**p_memHandle,unsignedlonglong*chunk_sizes,size_t num_chunks){#endifensure_context(device);//Define memory allocation properties CUmemAllocationProp prop={};//Allocate memory using cuMemCreate CUDA_CHECK(cuMemCreate(p_memHandle,size,&prop,0));if(error_code!=0){return;}CUDA_CHECK(cuMemMap(d_mem,size,0,*p_memHandle,0));if(error_code!=0){return;}CUDA_CHECK(cuMemSetAccess(d_mem,size,&accessDesc,1));if(error_code!=0){return;}

在睡眠模式下,使用VMM可以确保唤醒后CUDA Graph无需重新编译,从而显著提升框架的启动速度。睡眠模式与冷启动的对比[11]


SGLang的睡眠模式与vLLM的功能相似,其主要目的同样是减少启动阶段的时间开销,从而提升强化学习(RL)的整体迭代速度。在SGLang中,该模式分为两个步骤:释放显存(Release Memory)与恢复显存(Resume Memory),并通过标签(tag)控制权重与KV Cache的释放与恢复。

c> PD分离与混合部署热切换
与动态热加载类似,但切换前后仍为同一模型。例如在MoE、PD形态下流量不足时,可收缩D侧实例,并将P实例快速切到混合部署等形态,以节省碎片资源。

角色切换能丰富调度策略,但收益因场景而异,并非总是净正。在系统尚不够稳定时,故障成本可能压过细粒度切换带来的收益,此时粗粒度实例调度有时更稳妥。

小结
PD分离通过阶段化资源分配缓解Prefill与Decode的资源错配,是推理工程的重要选项,但单一静态形态难以应对MoE稀疏、多模型流量与实例粒度固定等现实约束。弹性伸缩把优化从整条P/D实例粒度推进到更细的容量与配比,在KV pool等基础设施就绪时,可在部分场景换取可观的吞吐增益。角色切换则在实例不退出的前提下扩展调度空间,需与Prefix cache、分布式KV及稳定性权衡一并设计。总体思路是:以PD分离为基座,用弹性与切换补齐其在动态负载下的短板,并按成熟度在细粒度策略与粗粒度调度之间取舍。


参考:

  • [1]https://zhuanlan.zhihu.com/p/1952393747112367273
  • [2]https://llm-d.ai/docs/architecture
  • [3]https://github.com/vllm-project/aibrix
  • [4]https://docs.ray.io/en/latest/serve/llm/index.html
  • [5]https://developer.nvidia.cn/dynamo
  • [6]https://github.com/vllm-project/vllm/issues/20336
  • [7]https://github.com/vllm-project/vllm-ascend/issues/3380
  • [8]https://github.com/vllm-project/vllm-ascend/pull/5822
  • [9]https://github.com/vllm-project/vllm-ascend/pull/5063
  • [10]https://github.com/vllm-project/vllm/blob/main/docs/features/sleep_mode.md
  • [11]https://blog.vllm.ai/2025/10/26/sleep-mode.html

InfraTech申明:未经允许不得转载!