Skip to content

分离式预填充(实验性)

本页面向您介绍 vLLM 中的分离式预填充功能。

Note

此功能为实验性功能,可能会发生变化。

为什么需要分离式预填充?

主要有两个原因:

  • 分别调优首字节延迟(TTFT)和字间延迟(ITL)。分离式预填充将 LLM 推理的预填充和解码阶段放在不同的 vLLM 实例中。这使您可以为调优 TTFT 而不影响 ITL,或为调优 ITL 而不影响 TTFT,分配不同的并行策略(例如 tppp)。
  • 控制尾部 ITL。没有分离式预填充时,vLLM 可能在解码一个请求期间插入一些预填充任务。这会增加尾部延迟。分离式预填充可以帮助您解决此问题并控制尾部 ITL。使用适当的块大小进行分块预填充也可以实现相同目标,但在实践中很难确定正确的块大小值。因此,分离式预填充是控制尾部 ITL 更可靠的方式。

Note

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

使用示例

请参考 examples/online_serving/disaggregated_prefill.sh 了解分离式预填充的示例用法。

目前支持 5 种类型的连接器:

--kv-transfer-config '{"kv_connector":"MultiConnector","kv_role":"kv_both","kv_connector_extra_config":{"connectors":[{"kv_connector":"NixlConnector","kv_role":"kv_both"},{"kv_connector":"ExampleConnector","kv_role":"kv_both","kv_connector_extra_config":{"shared_storage_path":"local_storage"}}]}}'

对于 NixlConnector,您还可以指定一个或多个 NIXL_Backend。例如:

--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_both", "kv_buffer_device":"cuda", "kv_connector_extra_config":{"backends":["UCX", "GDS"]}}'
  • OffloadingConnector:启用将 KV 数据卸载到 CPU 内存,自定义 CPU 块大小(以 tokens 为单位)和分配的总 CPU 内存字节数:
--kv-transfer-config '{"kv_connector":"OffloadingConnector","kv_role":"kv_both","kv_connector_extra_config":{"block_size": 64, "cpu_bytes_to_use": 1000000000}}'

性能测试

请参考 benchmarks/disagg_benchmarks 了解分离式预填充的性能测试。

开发

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

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

分离式预填充的关键抽象:

  • Connector:Connector 允许 kv consumerkv producer 获取一批请求的 KV 缓存。
  • LookupBuffer:LookupBuffer 提供两个 API:insert KV 缓存和 drop_select KV 缓存。insertdrop_select 的语义类似于 SQL,其中 insert 将 KV 缓存插入到缓冲区,drop_select 返回匹配给定条件的 KV 缓存并将其从缓冲区中删除。
  • Pipe:用于张量传输的单向 FIFO 管道。它支持 send_tensorrecv_tensor

Note

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

下面的图展示了上述 3 个抽象是如何组织的:

分离式预填充抽象

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

分离式预填充工作流程

图中的 buffer 对应 LookupBuffer 中的 insert API,drop_select 对应 LookupBuffer 中的 drop_select API。

现在,vLLM 中的每个进程都将有一个对应的连接器。具体来说,我们有:

  • 调度器连接器:位于与调度器进程同一进程中的连接器。它调度 KV 缓存传输操作。
  • 工作连接器:位于工作进程中的连接器。它们执行 KV 缓存传输操作。

下面的图展示了上述 2 个连接器是如何组织的:

分离式预填充高层设计

下图展示了工作连接器如何与注意力模块配合,实现逐层的 KV 缓存存储和加载:

分离式预填充工作流程

第三方贡献

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

我们推荐三种实现方式:

  • 完全自定义连接器:实现您自己的 Connector,调用第三方库发送和接收 KV 缓存,等等(比如编辑 vLLM 的模型输入以执行自定义预填充)。这种方法为您提供最大控制权,但存在与未来 vLLM 版本不兼容的风险。
  • 数据库类连接器:实现您自己的 LookupBuffer,支持 insertdrop_select API,就像 SQL 一样。
  • 分布式 P2P 连接器:实现您自己的 Pipe,支持 send_tensorrecv_tensor API,就像 torch.distributed 一样。