news 2026/9/2 7:21:59

【自用】AI infra相关:PD分离

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【自用】AI infra相关:PD分离

在LLM推理过程中,prefill阶段和decode阶段具有截然不同的计算特性:

  • prefill阶段需要并行处理整个输入序列来生成首个token,属于计算密集型操作。
  • decode阶段逐个生成后续token,需要频繁访问kv cache,属于内存密集型操作。

传统的continuous batching将两个阶段混合处理,导致互相干扰,难以同时满足TTFT(首token延迟)和TPOT(token间延迟)的严格要求。为了解决这一问题,PD分离框架应运而生,通过将prefill和decode分配到不同的gpu实例上,针对各自特性进行专门优化。这种分离式设计不仅消除了阶段间的干扰,还能显著提升系统的有效吞吐量(Goodput),为大规模LLM服务提供了更优的解决方案。

一、吞吐量(Throughput) vs 有效吞吐量(Goodput)

目前,大多数LLM都以吞吐量作为主要性能指标——即单位时间内处理的请求数(RPS)或生成的token数。

实际上,下游应用的类型多种多样,它们在用户体验上的延迟需求各异,因此需要满足的服务等级目标(SLO)也存在显著差异。大模型服务中最常用的SLO包括:

  • TTFT(time to first token):首token响应延迟,直接影响用户的等待体验。
  • TPOT(time per output token):衡量两个连续生成的token之间的平均延迟,决定交互的流畅程度。

例如,实时聊天机器人更关注低TTFT以保证响应及时,而TPOT只需快于人类阅读速度(约250词/分钟)即可;相反,分档摘要则更强调TPOT,一遍更快地产生完整摘要。

单纯依赖吞吐量作为指标,并不能反映延迟表现,系统看似处理了大量请求,但其中不少未能满足SLO,最终呈现给用户的仍是不理想的服务体验。

Throughput:通常指系统单位时间内处理的token数或请求数。很多工作把『提高吞吐量』作为主要优化目标,但在实际场景下这并不直接代表用户体验。

Goodput:指系统在满足延迟约束(如TTFT/TPOT SLO)的前提下,每秒完成的有效请求数。与单纯的吞吐量相比,Goodput是更优的衡量指标,因为它能够体现请求在满足SLO情况下的吞吐水平,从而同时反映成本效益和服务质量。

Goodput(P90 TTFT < 200ms 且P90 TPOT < 50ms)表示在至少90%的请求同时满足TTFT < 200ms和TPOT < 50ms的条件下,系统所能维持的最大每秒请求数。

eg:某应用的吞吐量为10 RPS(每秒请求数),但由于延迟约束的限制,只有3 RPS的请求满足SLO,因此该系统的Goodput仅为3 RPS。

二、prefill和decode共置导致干扰

在LLM服务中请求的生命周期通常包含两个阶段:prefill(生成首个token)和decode(逐步生成后续token)。大多数现有系统(如vllm,TensorRT-LLM)采用continuous batching集数,将prefill和decode混合在一起统一批处理。这种方式确实能够提升整体吞吐量,但由于两者计算特性和SLO目标差异显著,将它们共置在同一gpu上往往不理想。

如下图所示,continuous batching会带来明显干扰。当prefill和decode被放在同一批次时,decode请求的延迟(TPOT)会被显著拉长,而prefill请求的首token延迟(TTFT)也会有所增加。

图中展示了三种不同的执行方式:

1P+nD(棕色):1个prefill与n个decode混合批处理。

nD(蓝色):仅包含decode请求的批处理。

prefill-only(红色虚线):仅运行prefill请求的延迟。

在prompt长度为128时,相比仅包含decode的请求,延迟增加约1.8倍;而当prompt长度为1024时,干扰效应显著放大,decode延迟提升至12.6倍。

由于这种干扰,当服务必须同时满足TTFT和TPOT的SLO时,系统往往需要进行资源的过度配置才能达到延迟目标,尤其是在任一SLO要求较严格的情况下。

三、PD分离的整体思路

直观的思路:将prefill和decode分离到不同的gpu上,并为每个阶段定制并行策略。这自然解决了前面提到的两个问题:

  • 没有干扰:prefill和decode各自独立运行,更快地完成计算,也更容易满足各自的SLO。
  • 资源分配和并行策略解耦:可以针对prefill和decode分别优化。

当一个请求到达系统时,它会先被分配到prefill worker完成prefill阶段;随后系统将其中间状态(主要是kv cache)迁移到decode worker,并执行多步decode以生成后续token;当生成完成后,请求才会离开系统。

四、分离式推理架构的优化方向

(4.1)算力与存储

prefill阶段:拥有计算受限的性质(compute-bound),特别是在请求流量较大,用户的prompt也较长的情况下。prefill阶段算完kv cache并发给decode阶段后,理论上prefill就不再需要这个kv cache了(当然也可以采用LRU等策略对kv cache的保存做管理,而不是一股脑地清除)

decode阶段:拥有内存受限的性质(memory-bound),因为逐个token的生成方式,decode要频繁从内存中读取kv cache,同时也意味着它需要尽可能保存kv cache。

因此在分离式框架下,计算和存储可以朝着两个独立的方向做优化。

(4.2)batching策略

  • prefill阶段:随着batch_size的增加,吞吐量的提升很快趋于平缓这是因为prefill属于compute-bound,当batch中的总token数超过一定规模后,GPU的计算能力已经被完全吃满,再增加请求只会延长整体处理时间,而不会带来明显的吞吐提升。
  • decode阶段:随着batch_size的增加,吞吐量的增长趋势越来越显著。这是因为decode阶段是memory-bound,即相比于计算,读写数据的时间要更多,所以在decode阶段中,如果我们能提升batch_size,就能把计算强度提起来,吞吐量就上去了。

在分离架构下,我们可以针对prefill和decode的特性对Batching策略分别进行优化:

  • 具体来说,对于prefill实例,需要事先结合特定的llm和gpu做性能分析,找出输入长度的临界点——一旦超过这个点,prefill就会进入compute-bound,此时增加batch_size只会拖慢整体处理速度。在实际应用中,用户的prompt往往已有数百个tokens,因此prefill的batch_size通常保持较小。
  • 相对的,decode阶段更适合采用较大的batch_size,已充分提升gpu利用率和整体吞吐。

(4.3)并行策略

由于prefill和decode具有不同的计算模式和延迟目标,这两个阶段的最佳并行策略不相同。例如,当TTFT要求严格而TPOT要求相对宽松时,prefill更适合采用张量并行来满足低延迟,而decode则通常采用数据并行或流水线并行来提升吞吐。

五、kv cache传输

PD分离带来的代价是需要在prefill和decode的gpu之间传输中间状态(即kv cache)。

(5.1)kv cache传输开销

初看之下,kv cache是llm推理中巨大的内存开销,而gpu之间kv cache的传输似乎会成为瓶颈。然而,DistServe的论文中展示了相反的结果:通过合理的放置,kv cache的传输开销可以被有效地最小化,甚至低于一次decode步骤的时间,这得益于当今高速互联网络。

假设在gpu之间使用8通道PCle 5.0x16(每条链路64GB/s)作为节点内互联。对于一个包含2048tokens的请求,在服务OPT-175B时传输kv cache的延迟可以估算如下:

Latency=2048 tokens * (4.5MB/token)/(64GB/s * 8)=17.6 ms

对于 OPT-175B,延迟小于单次 decode 步骤(在 A100 上约为 30-50 毫秒)。对于更大的模型、更长的序列或更先进的网络(例如带宽为 600GB/s 的 A100-NVLink),如下图所示,与单次 decoe 步骤相比,KV cache 传输相关的相对开销变得不那么显著。总之,通过精心安排 prefill 和 decode 工作节点以利用高带宽网络,可以有效隐藏 KV cache 传输的开销。

(5.2)kv cache传输方式

目前kv cache的传输主要有两种方式:中心存储和点对点(P2P),当然在实际系统中也可能采用两种结合的混合方案。

  • 中心存储:建立一个跨设备的kv cache,由它统一管理kv cache的增删查和传递等操作。prefill和decode实例只需与这个kv store交互,负责写入或读取数据。
  • p2p:每个实例独立管理自己的存储。例如,一个prefill实例完成计算后,会直接与目标decode实例建立通信,将kv cache传过去,不依赖统一的中介。

两种方式各有优劣:

  • 中心存储:更适合构建大规模集群,能充分利用多种存储介质和传输通道,并提升计算结果的复用效率,但在某些场景下性能可能受限,同时系统维护成本高。
  • p2p:架构很简单,性能表现通常更好,但在扩展性和链路稳定性方面会面临挑战。

(5.3)kv cache传输的网络堆栈

现有的物理数据链路可以分为3类:

  • Direct,即GPU之间通过高速告诉直连链路(如NVLink或HCCS)相互连接。在这种情况下,可以利用底层的内存拷贝原语或集体通信库来完成数据传输。
  • Direct-NIC,即GPU通过其配套的网卡(NIC)进行通信。在这里,可以使用定制化的库,通过PCle和以太网(或InfiniBand)进行数据传输。
  • Indirect,即当GPU之间没有直接链路时,必须通过其CPU的DRAM中转数据,从而带来额外的内存拷贝开销。

(5.4)Kv cache传输粒度

  • 请求级:等到prefill阶段完成后,将kv cache一次性传输。这种方式的好处是能够减少网络传播次数,因为每次传输的数据量更大,从而降低了通信开销。然而当kv cache大小较大时,会影响TTFT。
  • 层级:spilitwise通过在prefill阶段的计算与kv cache传输之间实现重叠来优化性能。每一层计算完成后,都会异步传输该层的kv cache,同时继续执行下一层的计算,从而降低传输开销。层级传输还能带来额外优势,例如更早启动decode阶段,以及更早释放prefill端的内存。层级kv cache传输与下一层的prefill计算并行进行,这需要逐层的细粒度同步以确保正确性,因此可能带来性能干扰并增加TTFT,尤其是在小prompt场景下,不过对于小prompt来说,kv cache的总体规模很小,不需要层级传输来隐藏延迟。由于在计算开始时批次中的token数是已知的,splitwise会选择最合适的kv cache传输方式:小prompt使用序列化传输,而大prompt使用层级传输。
  • 块级:TetrilInfer在PD分离的基础上,还会将输入的prompt划分为固定大小的chunk,以便让GPU始终运行在接近计算饱和的状态。

(5.5)vllm的PD分离

vllm提供了kv connector作为管理实例间kv cache交换的抽象层,它提供统一接口来实现kv cache的保存、加载与传输,使不同的vllm实例(如prefill和decode实例)能够高效共享计算结果。通过实现这一接口,各类connector(例如通过文件系统的SharedStorageConnector、通过网络的NixlConnector等)提供了灵活的kv cache传输方案,从而支持PD分离等高级功能。

KVConnectorBase_V1是所有connector的基类,他是一个抽象类,定义了一下API:

  • scheduler侧方法:
    • build_connector_meta:构建元数据,shceduler告诉worker需要保持/加载哪些kv cache。
    • get_num_new_matched_tokens:获取远端已计算的kv cache的token数量
    • update_state_after_alloc:block开辟后,更新connector的状态。
  • worker侧方法:
    • start_load_kv:从connector buffer加载kv cache,消费端调用。
    • wait_for_layer_load:阻塞直到指定层加载结束,消费端调用。
    • save_kv_layer:将vllm的kv buffer中某一层的kv cache保存到connector buffer中,生产端调用。
    • wait_for_save:阻塞直到所有保存操作完成,生产端调用。

vllm v1中connector有两个执行角色:scheduler_connector和worker_connector,分别在scheduler线程和worker线程中执行。shceduler负责指挥worker进行kv cache的传递,两者之间的信息桥梁是元数据(KVConnectorMetadata),worker通过metadata知道哪些kv值需要从远端加载。

当前vllm支持5种类型的connector,分别为:

SharedStorageConnector:vllm中最简单的kv connector实现,通过共享文件系统(如本地磁盘或NFS)在prefill和decode之间传递kv cache,使用MD5哈希生成唯一文件名来存储和检索每个请求的kv cache,prefill实例将每层的kv cache序列化为SafeTensors格式保存到指定路径,decode实例根据相同的token_ids计算哈希值找到对应文件并加载,整个过程没有显式的网络传输,完全依赖文件系统的读写操作。

P2pNcclConnector:基于NCCL(NVIDIA Collective Communications Library)实现的高性能kv connector,通过NCCL的send/recv原语实现kv cache在不同gpu之间的点对点传输,避免了文件系统的开销。

NixlConnector:使用NIXL(NVIDIA Inference Xfer Library)库来加速GPU之间以及异构内存与存储之间的kv cache传输。

LMCacheConnectorV1:通过与LMCache集成实现kv cache的外部存储与检索,支持多种存储后端(如CPU内存、本地文件系统、Redis、InfiniStore等)。LMCache通过重用缓存的kv cache来减少推理时间,消除冗余计算,适用于跨请求或跨会话的kv cache共享场景。

MultiConnector:允许同时使用多个kv connector来实现kv cache的传输,它的核心逻辑是从第一个能提供可用token的connector加载kv cache,但会向所有connector保存数据。multiconnector适用于需要同时向多个存储后端保存Kv cache的场景,比如同时保存到本地存储或远程存储,提供数据冗余和可靠性保障。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 7:21:44

东南DX7多媒体系统升级包刷写实操:从版本校验到卡顿修复

简介&#xff1a;东南DX7多媒体系统升级包面向DX7车主&#xff0c;用于解决2015年老版本车机功能与稳定性问题&#xff0c;升级后可将系统更新至2016年7月版本。包内共13个文件&#xff0c;包含系统固件bin、升级主程序exe、校验脚本bat、配置文件xml等类型&#xff0c;整体约1…

作者头像 李华
网站建设 2026/9/2 7:16:37

基于STM32F407与RTOS的双电机FOC控制方案解析与实现

简介&#xff1a;本资源是一套基于STM32F407的双电机FOC&#xff08;磁场定向控制&#xff09;完整工程&#xff0c;面向嵌入式电机控制工程师、高校电赛/毕设学生及ROS机器人开发者&#xff0c;解决高性能永磁同步电机&#xff08;PMSM&#xff09;实时闭环控制难题&#xff0…

作者头像 李华
网站建设 2026/9/2 7:15:54

C语言医院挂号系统:从结构体到文件操作的综合实践指南

简介&#xff1a;本资源是一个基于C语言开发的轻量级医院挂号系统实现&#xff0c;面向C语言初学者与课程设计实践者&#xff0c;旨在通过真实业务场景帮助学习者掌握结构体设计、文件持久化、链表动态管理、用户交互及模块化函数编程等核心技能。压缩包为ZIP格式&#xff0c;大…

作者头像 李华
网站建设 2026/9/2 7:15:20

Focas1/2+协议深度解析:C/C++直连Fanuc数控系统实战指南

简介&#xff1a;本资源是面向工业自动化开发工程师、数控系统集成人员及C/C嵌入式开发者的技术资料包&#xff0c;聚焦FANUC数控系统FOCAS 1/2通信接口的工程化应用&#xff0c;解决设备数据采集、远程监控与参数动态配置等核心问题。压缩包共105个文件&#xff0c;涵盖17个DL…

作者头像 李华
网站建设 2026/9/2 7:13:40

OpenFAST v3.2.1源码解析:从架构到二次开发实战

简介&#xff1a;风电仿真软件 OpenFAST 3.2.1 完整源码压缩包&#xff0c;面向风电领域工程师与科研人员&#xff0c;适用于风力机气动、结构、水动力等多学科耦合建模及二次开发。包体为 zip 格式&#xff0c;约 434.11MB&#xff0c;未提供文件数量与类型明细&#xff0c;但…

作者头像 李华