立即注册找回密码

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

手机动态码快速登录

手机号快速注册登录

搜索

图文播报

查看: 694|回复: 0

[讨论] PD分离-XpYd系统服务化

[复制链接]
发表于 2025-3-17 21:40 | 显示全部楼层 |阅读模式

登陆有奖并可浏览互动!

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录 手机动态码快速登录

×
背景

关于PD分离技术,到底是使用1p1d还是XpYd,目前主要业界主要有2类实践:

  • XpYd,顾名思义,会有X个Prefill实例和Y个Decode实例,通过调整X和Y来控制Prefill和Decode的数量;其实X和Y一般都不会很大,因为X和Y会构成一组(Group)对外提供服务,集群中可能有很多组该服务,参考 P/D-Serve 论文。
  • 1p1d,顾名思义,只有一个p实例和一个d实例,如Deepseek R1推理系统,Prefill采用了32路 DP + MoE并行,Decode采用了144路的DP + MoE并行,有人可能说,Deepseek R1的Prefill实例也是X个,Decode的实例是y个,个人觉得应该不会,因为Prefill和Decode的一个实例真的太多了,如果还是X和Y的组合,个人觉得容错、分布式、通信、请求调度等都过于复杂,而且可能真的也不需要了。个人能力和见识有限,如有错误还请勿喷,纯技术学习,期待Deepseek大佬解惑。
其实Deepseek R1的推理系统本身也是XpYd的架构,因为Prefill和Decode都是做了数据并行,无论是请求调度还是KV Cache传输角度,都是一个XpYd问题。
笔者本文希望借社区的一些文档,分析一下XpYd的一些技术。关于XpYd,社区可以借鉴的文档,笔者贴在了参考里,有兴趣可以直接观看。当谈到XpYd问题,先抛出2个问题:
1,X个Prefill和Y个Decode,请求是如何流转的,这本质上是一个分布式服务问题,XpYd服务化。
2,KV Cache是如何传传输。
XpYd-服务化

系统整体架构



当确定分离式架构是XpYd了,那么整个系统该如何协作对外服务。P/D-Serve里提出的一个系统设计如上图所示,这里有一个P/D Group的概念,Xp和Yd构成了一个Group,系统里会有很多个这个Group。请求过来了,天然的就是一个2层的请求调度逻辑。第一层,调度到具体的P/D Group,第二层则是在P/D Group内选择一个Prefill实例和一个Decode实例。
服务化注册



调度器是怎么知道P/D Group有哪些以及每个Group有哪些Prefill和Decode节点呢?每个节点启动的时候,把自己的角色和ip注册给zookeeper即可,这样调度器就可以去zookeeper拿到这些信息。关于这部分内容如果不是很清楚的可以搜搜RPC、分布式服务框架、注册中心之类的文章。
那么一个节点如何知道自己属于哪个Group、属于Prefill还是Decode角色呢?这个也简单,可以自己主动去另一个地方问撒。但是去zookeeper问是没用的,他指着你给他信息呢。
不知道自己是谁,问是给你调度起来的人,K8S给你调度起来的对吧,他会对你负责的,当然这些功能也是得写代码的。
举个例子吧,针对XpYd这一组,K8S负责启动 X + Y个机器(暂且先认为每个实例单机8卡),K8S会告诉前X机器是Prefill节点、后Y个机器是Decode节点,至于Group的话,随便来吧,保证唯一就好,对于全局调度器,才不管你的group名字呢。全局调度器只需要知道有多少group,以及group内的小代理实时告诉全局调度器自己还能不能扛得住就好。
动态调整比例



对于XpYd,如果服务扩容,一般再扩一个Group就好,但是万一有时候,希望把X扩容到X + 1可能也是合理的。
上图就是扩容之后的图示,左边是扩容Decode节点,右边是扩容Prefill节点。本质上,就是提供动态发现、动态建立新的通信的能力。比如扩容1个Prefill实例,那么Prefill实例会携带着自己的Group去注册到zookeeper,这时候他就算启动成功了。他会拿这个Group问zookeeper还有哪些Decode是这个组的,同时,属于这个组的所有的Decode其实也可以通过zookeeper知道有一个Prefill加入了,这时候,就可以建立新的通信了。总之有了zookeeper,你什么都好做。
容错



容错核心点有2个:

  • 发现故障:有了zookeeper、K8S的健康检查、再加上XpYd中Prefill和Decode节点是全互联的,这挂了一个节点要发现不了,那节点一定是有奸细。
  • 剔除节点:Prefill或者Decode节点挂了,问题也不大,反正全局调度器和组内调度器都发现了,就把它摘了,K8S负责重启,重启之后再加入组里,最大的问题是某个节点挂了,别和他连着的节点发消息把自己也发挂了或者干死锁了。
XpYd-KV Cache传输方案

vLLM已经对XpYd进行了设计,该方案目前设计如下。
当前的设计是异步架构, 通过独立的 KVCache 存储将Prefill节点和Decode节点分离。 这种解耦确保了Prefill节点无需等待Decode节点来获取 KVCache。


Prefill实例处理输出长度为 1 的请求, 并将 KV 缓存放入 KV 缓存存储中。 该存储将实现为通用接口, 底层提供者可以是 LMCache、 Mooncake、 Valley 等。
控制路径可以通过直接的 HTTP 调用或消息队列来实现。 设置完成后, Decode 实例从消息队列或直接从 API 调用接收请求, 然后从 KVCache 存储中获取 KVCache, 从而跳过Prefill阶段, 直接进入Decode阶段。
关于异步还是同步,vLLM团队给了如下解释
除了上述的异步架构之外, 另一种选择是直接将Prefill节点和Decode节点连接起来以实现 KVCache 的传输。 这种方法有可能减少 TTFT(首次响应时间) , 因为KVCache 只传输一次而非两次。 然而, 这种设计更容易因负载不均衡、 节点故障、网络拥塞等问题而出现停滞。 因此, vLLM社区更倾向于异步设计。 此外, 一旦需要全局KVCache 复用, 减少网络开销的优势也将不复存在。
参考


原文地址:https://zhuanlan.zhihu.com/p/30619735151
楼主热帖
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册 微信登录 手机动态码快速登录

本版积分规则

关闭

官方推荐 上一条 /3 下一条

快速回复 返回列表 客服中心 搜索 官方QQ群 洽谈合作
快速回复返回顶部 返回列表