分离式预填充(实验性)#

本页介绍 vLLM 中的分离式预填充特性。

注意

此功能为实验性功能,可能会发生更改。

为什么使用分离式预填充?#

两个主要原因

  • 分别调整首 token 延迟 (TTFT) 和 token 间延迟 (ITL)。 分离式预填充将 LLM 推理的预填充和解码阶段置于不同的 vLLM 实例中。 这使您可以灵活地分配不同的并行策略(例如 tppp)来调整 TTFT 而不影响 ITL,或调整 ITL 而不影响 TTFT。

  • 控制尾部 ITL。 在没有分离式预填充的情况下,vLLM 可能会在一个请求的解码过程中插入一些预填充作业。 这会导致更高的尾部延迟。 分离式预填充可以帮助您解决此问题并控制尾部 ITL。 使用适当 chunk 大小的分块预填充也可以达到相同的目的,但实际上很难确定正确的 chunk 大小值。 因此,分离式预填充是控制尾部 ITL 的更可靠方法。

注意

分离式预填充 不会 提高吞吐量。

使用示例#

请参考 examples/online_serving/disaggregated_prefill.sh 以获取分离式预填充的使用示例。

基准测试#

请参考 benchmarks/disagg_benchmarks/ 以获取分离式预填充的基准测试。

开发#

我们通过运行 2 个 vLLM 实例来实现分离式预填充。 一个用于预填充(我们称之为预填充实例),另一个用于解码(我们称之为解码实例),然后使用连接器将预填充 KV 缓存和结果从预填充实例传输到解码实例。

所有分离式预填充的实现都在 vllm/distributed/kv_transfer 下。

分离式预填充的关键抽象

  • 连接器 (Connector):连接器允许 KV 消费者KV 生产者 检索一批请求的 KV 缓存。

  • 查找缓冲区 (LookupBuffer):LookupBuffer 提供两个 API:insert KV 缓存 和 drop_select KV 缓存。 insertdrop_select 的语义类似于 SQL,其中 insert 将 KV 缓存插入缓冲区,而 drop_select 返回与给定条件匹配的 KV 缓存并将其从缓冲区中删除。

  • 管道 (Pipe):用于张量传输的单向 FIFO 管道。 它支持 send_tensorrecv_tensor

注意

insert 是非阻塞操作,但 drop_select 是阻塞操作。

下图说明了以上 3 个抽象是如何组织的

Disaggregated prefilling abstractions

分离式预填充的工作流程如下

Disaggregated prefilling workflow

buffer 对应于 LookupBuffer 中的 insert API,而 drop_select 对应于 LookupBuffer 中的 drop_select API。

第三方贡献#

分离式预填充与基础设施高度相关,因此 vLLM 依赖于第三方连接器来实现生产级别的分离式预填充(并且 vLLM 团队将积极审查和合并用于第三方连接器的新 PR)。

我们推荐三种实现方式

  • 完全自定义连接器 (Fully-customized connector):实现您自己的 Connector,并调用第三方库来发送和接收 KV 缓存,以及更多功能(例如编辑 vLLM 的模型输入以执行自定义预填充等)。 这种方法为您提供了最大的控制权,但也存在与未来 vLLM 版本不兼容的风险。

  • 类数据库连接器 (Database-like connector):实现您自己的 LookupBuffer 并支持 insertdrop_select API,就像 SQL 一样。

  • 分布式 P2P 连接器 (Distributed P2P connector):实现您自己的 Pipe 并支持 send_tensorrecv_tensor API,就像 torch.distributed 一样。