本文由无问芯穹技术团队原创,分享在端、云两侧推理系统工作中的思考和心得,无问芯穹官方知乎账号同步发表。
Semi-PD是由无问芯穹推出的推理引擎工作,不同于传统的分离式、融合式工作,我们提出了P/D半分离的调度策略,名为计算分离存储融合架构,兼顾分离式延迟干扰小和融合式存储不冗余的优势。我们的优化目标是: 在给定资源和SLO的前提下,最大化goodput。相比于开源的SOTA实现,我们Goodput提升1.55-1.72x,单请求平均端到端时延提升1.27-2.58x。
开源仓库地址:
技术报告:
知乎地址:
zhuanlan.zhihu.com/p/190013520…
不同于技术报告,本文凝练了我们的动机与主要的设计与实现,也分享一下这篇研究工作的的心路历程,希望通过这样的方式跟大家交流交流,共同进步。更多的细节可以参考技术报告中的内容。开源的版本是基于SGlang的实现,欢迎大家尝试。
01
分离式与融合式辨析
当前的调度工作分为融合式和分离式两类:
融合式调度策略:即prefill和decode在同一个实例内,大体可以分为两种调度方法(decode优先太差了,不在此讨论),第一种是prefill优先的,当有新的请求进入系统时,会暂停decode优先处理prefill,这种调度方法会令TPOT比较差,于是有了另一种方案: chunked prefill,即每次推理都会计算decode加一部分prefill,用一个给定的窗口大小(chunk size)控制每轮prefill token数,以达到均衡P和D之间影响的目的。
图1. 援引自Sarathi-Serve论文
我们最初也聚焦在融合式的架构上,由于系统的负载状态是实时变化的,融合式架构下不同请求的Prefill和Decode阶段干扰严重,会导致不同请求的TTFT和TPOT存在比较复杂的“分配不均”问题,具体包括两个方面:1)同一个请求的TTFT(TPOT)是满足延迟要求的,甚至还有余量,但是TPOT(TTFT)却不满足延迟要求;2)不同的请求下,请求R1的延迟(TTFT,TPOT)满足要求,甚至还有余量,但是请求R2的延迟(TTFT,TPOT)却不满足要求。为此,我们改进了chunked Prefill,设计了更复杂的考虑上述“分配不均”的调度算法,这个工作被MLsys接收(mlsys.org/virtual/202…
分离式调度策略:即为Prefill和Decode提供不同的运行实例,Prefill实例做完后将kvcache传输到Decode实例上,进行后续的推理,代表的工作如splitwise,Distserve,mooncake,deepseek以及NVIDIA Dynamo等。将P和D分开后,相互干扰这个问题就天然地被解决了,但也带来了新的问题。
-
权重冗余:权重多存了一份,对于集群规模不大的情况下,这部分额外多存的权重的影响是不可忽略的。例如在一体机场景下,存储资源有限,难以使用PD分离的策略。
-
存储不均衡:serving中大部分时间是被decode占据了,kv在decode instance中驻留时间较长,当decode kv用的比较满的时候,prefill还有很多余量。虽然集群规模大了之后,采用中心化的KV-Cache管理能缓解这一问题,但是在小规模集群上仍然难以解决。
-
KV传输:Prefill做完需要将kvcache传输到Decode实例上,会带来额外的开销。
-
配比调整:给定Prefill和Decode资源后,想要reschedule资源配比开销较大。
事实上,上述的问题的核心根源是为了引入PD分离所做的牺牲,而这个牺牲的关键是PD之间无法像融合式架构一样能共享存储。于是我们就想,我们能不能既要又要呢。于是就有了本文,计算分离存储融合架构,我们不仅提高了存储效率,也做到kvcache传输和资源配比调整0开销。
02
系统架构
图2. semi-PD架构图
不同于传统方案将prefiil和decode任务分别放在不同的计算卡上,Semi-PD 让 P 和 D 共享同一张卡,各自占用部分计算资源(可以想象为“半张卡”)。同时,模型权重和 KV cache 只需存储一份,因此我们称为计算分离存储融合。这种设计允许我们灵活调整 P 和 D 的资源占比(比如 70% 给Prefill,30% 给Decode),从而更细粒度地调优TTFT和TPOT。
P/D分离的系统实现
我们基于多进程服务(Multi-Process Service, MPS)实现了计算资源分配。 MPS允许将特定数量的(SMs)分配给不同进程,从而在SM级别实现计算资源划分。Semi-PD接收(x, y)配置参数,其中x和y分别表示通过MPS分配给预填充(prefill)和解码(decode)进程的SM总量百分比。在进程间我们通过IPC来共享权重和kvcache,令prefill和decode实例可以读写同一块地址。
进程轮换机制。 在MPS中并不支持对已有进程的SM用量进行动态调整,因此,调整SM配比需要重新启动进程。在Semi-PD中,我们实现了一个两组进程轮换的机制(推理进程和休眠进程),在推理进程感知到切换信号时,会通信给休眠进程进行重置配比,不阻塞当前进程的推理。当休眠进程重置完毕后,会在推理进程当前step结束后进行角色切换,完成SM配比的更新。
图3. 基于IPC的进程间显存共享机制
统一的存储管理器。 在整个系统中,由于P和D是异步的,但KVcache的存储是共享的,所以我们需要cache block的分配具有原子性。我们将decode 实例作为 KV cache的主要管理者,负责为传入的请求分配上下文块,并随后将内存信息传递给 prefill 实例,确保kvcache的读写一致性。
动态资源分配
系统的核心目标是在满足服务级别目标(SLO)的前提下,尽可能提高请求处理能力,然而,prefill和decode负载在实际服务中是动态变化的,固定的资源分配策略往往难以应对这些变化,容易造成资源利用不均,我们提出了一种支持SLO感知的动态资源调整机制。该机制能够根据实时负载情况,动态调整资源划分比例(x, y),以更好地满足延迟约束和系统吞吐的双重目标。在资源分配算法中,我们会设置一个windows size,周期性地感知系统负载,以此来作为调整的输入信号。当我们发现这个周期违反了SLO,我们会通过预测合理的SM配比来reschedule整个系统的计算资源划分。我们通过预测(x,y)配比下的TTFT和TPOT来找到距离最近的调整点。
平衡预测模型的性能和精度是一件比较困难的事,预测模型越大latency越准确,但开销也会上升,在每次调度中间我们需要overhead足够小,否则会影响系统的推理效率。在实际实现中,我们改变了目标任务,迁移到一个相对简单的任务上,即不直接预测执行的latency,而是预测一个scale值,用当前的观测值乘上scale来计算在目标配比下的latency,从而计算出合理的SM配比。
03
实验结果
我们相信semi-PD是一种LLM调度的新选择,在小规模实例推理场景下(一体机场景),semi-PD是当前融合式架构非常有竞争力的替代者;在大规模集群分布式推理场景下,semi-PD作为一种新选择,可以很好地与P实例和D实例配合同时存在。
为了实验的公平性和完备性,我们跟融合式和分离式都进行了比较,其中我们在Distserve和SGLang上均做了实现,并且对齐了除schedule以外的其他可能引入误差的项(比如,我们替换了Distserve中部分kernel,保证一致性)。特别的,由于在我们选择deepseek对照组的时期,评测下来的结果是SGLang的性能最好,我们希望跟行业的SOTA进行比较,因而选择了SGLang做为codebase和实验对象。
Llama系列模型结果:
其中vllm-S对应splitfuse schedule,vllm-D对应default schedule即Prefill优先
图4. llama系列模型实例推理下的对比数据
Deepseek系列模型结果:
图5. deepseek模型实例推理场景下的对比结果
除此之外,我们进行了集群推理的实验,是基于NVIDIA Dynamo实现的。在集群推理中,Semi-PD可以以实例的方式进行集成,和P/D实例一起参与请求路由。我们认为Semi-PD在集群推理中主要优势在于应对请求的波动,原本集群的xPyD部署可能是按预设的负载特性来进行的,但实际面对负载变化时,再进行xPyD的调整具有比较大的开销。而Semi-PD可以在其中做这个资源分配变化的缓冲区,由于资源调整开销很小,而且仍然保持无延时干扰的特性,因此在这类型负载下能够带来显著的延时降低。
Deepseek-V2-Lite模型集群推理结果:
图6. 集群推理场景性能对比结果
图中的2P6D使用Dynamo部署2个prefill实例和6个decode实例,而1P3D4S则是用4个semi-PD实例代替了其中的1个prefill实例和3个decode实例。具体的实验设置细节可以参考我们的技术报告。
04
结语
希望semi-PD能为大模型推理的进步贡献一点力量。如遇问题,烦请斧正。