分离式预填充(实验性)¶
本页面为您介绍 vLLM 中的分离式预填充(Disaggregated Prefilling)功能。
注意
此功能尚处于实验阶段,后续可能会有变动。
为什么要进行分离式预填充?¶
主要有两个原因
- 分别调整首字延迟 (TTFT) 和输出吞吐延迟 (ITL)。分离式预填充将 LLM 推理的预填充(prefill)阶段和解码(decode)阶段放置在不同的 vLLM 实例中。这使您可以灵活地分配不同的并行策略(例如
tp和pp),以便在不影响 ITL 的情况下调整 TTFT,或者在不影响 TTFT 的情况下调整 ITL。 - 控制尾部 ITL。如果没有分离式预填充,vLLM 可能会在处理某个请求的解码过程中插入预填充任务,从而导致尾部延迟增加。分离式预填充有助于解决此问题并控制尾部 ITL。虽然带有合适块大小(chunk size)的分块预填充(Chunked prefill)也能达到同样的目标,但在实践中很难确定正确的块大小值。因此,分离式预填充是控制尾部 ITL 的一种更可靠的方法。
注意
分离式预填充并不会提高吞吐量。
使用示例¶
请参考 examples/online_serving/disaggregated_prefill.sh 获取分离式预填充的使用示例。
目前支持 6 种连接器
- ExampleConnector:参考 examples/offline_inference/disaggregated-prefill-v1/run.sh 获取 ExampleConnector 分离式预填充的使用示例。
- LMCacheConnectorV1:参考 examples/others/lmcache/disagg_prefill_lmcache_v1/disagg_example_nixl.sh 获取 LMCacheConnectorV1 分离式预填充的使用示例,该连接器使用 NIXL 作为底层 KV 传输协议。
- NixlConnector:参考 tests/v1/kv_connector/nixl_integration/run_accuracy_test.sh 获取 NixlConnector 分离式预填充的使用示例,该连接器支持完全异步的发送/接收。详细使用指南请参考 NixlConnector 使用指南。关于功能兼容性详情,请参考 NixlConnector 兼容性矩阵。
- P2pNcclConnector:参考 examples/online_serving/disaggregated_serving_p2p_nccl_xpyd/disagg_example_p2p_nccl_xpyd.sh 获取 P2pNcclConnector 分离式预填充的使用示例。
- MooncakeConnector:参考 examples/online_serving/disaggregated_serving/mooncake_connector/run_mooncake_connector.sh 获取使用示例。详细使用指南请参考 MooncakeConnector 使用指南。
- MultiConnector:利用
KVTransferConfig中已有的kv_connector_extra_config: dict[str, Any],将所有需要的连接器存储在有序的 kwargs 列表中,例如:
--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 块大小(以 token 为单位)以及分配的总 CPU 内存字节数。
--kv-transfer-config '{"kv_connector":"OffloadingConnector","kv_role":"kv_both","kv_connector_extra_config":{"block_size": 64, "cpu_bytes_to_use": 1000000000}}'
- FlexKVConnectorV1:参考 examples/offline_inference/prefix_caching_flexkv.py 获取 FlexKVConnectorV1 的使用示例。FlexKV 是用于超大规模 LLM 推理的分布式 KV 存储和多级缓存管理系统。
基准测试¶
请参考 benchmarks/disagg_benchmarks 获取分离式预填充的基准测试数据。
开发¶
我们通过运行两个 vLLM 实例来实现分离式预填充。一个实例用于预填充(我们称之为预填充实例),另一个用于解码(我们称之为解码实例),然后使用连接器将预填充实例中的 KV 缓存和结果传输到解码实例。
所有分离式预填充的实现均位于 vllm/distributed/kv_transfer 目录下。
分离式预填充的关键抽象
- Connector(连接器):连接器允许 KV 消费者从 KV 生产者中获取一批请求的 KV 缓存。
- LookupBuffer(查找缓冲区):LookupBuffer 提供两个 API:
insertKV 缓存和drop_selectKV 缓存。insert和drop_select的语义类似于 SQL,其中insert将 KV 缓存插入到缓冲区中,而drop_select返回匹配给定条件的 KV 缓存并将其从缓冲区中移除。 - Pipe(管道):用于张量传输的单向 FIFO 管道。它支持
send_tensor和recv_tensor。
注意
insert 是非阻塞操作,而 drop_select 是阻塞操作。
下图展示了上述三个抽象是如何组织的:
分离式预填充的工作流程如下:
其中的 buffer 对应 LookupBuffer 中的 insert API,drop_select 对应 LookupBuffer 中的 drop_select API。
现在 vLLM 中的每个进程都将拥有一个对应的连接器。具体来说,我们有:
- 调度器连接器(Scheduler connector):位于与调度器进程相同进程中的连接器。它负责调度 KV 缓存的传输操作。
- 工作进程连接器(Worker connectors):位于工作进程中的连接器。它们执行 KV 缓存的传输操作。
下图展示了上述两个连接器是如何组织的:
下图显示了工作进程连接器如何与注意力模块配合,实现分层级的 KV 缓存存储和加载:
第三方贡献¶
分离式预填充与基础设施高度相关,因此 vLLM 依赖第三方连接器来实现生产级别的分离式预填充(vLLM 团队将积极审查并合并针对第三方连接器的新 PR)。
我们推荐三种实现方式:
- 完全自定义连接器:实现您自己的
Connector,并调用第三方库来发送和接收 KV 缓存,以及进行更多其他操作(如编辑 vLLM 的模型输入以执行自定义预填充等)。这种方法为您提供了最大的控制权,但存在与未来 vLLM 版本不兼容的风险。 - 类似数据库的连接器:实现您自己的
LookupBuffer,并像 SQL 一样支持insert和drop_selectAPI。 - 分布式 P2P 连接器:实现您自己的
Pipe,并像torch.distributed一样支持send_tensor和recv_tensorAPI。



