NixlConnector 使用指南¶
NixlConnector 是一个高性能 KV 缓存传输连接器,专为 vLLM 的分离式预填充(disaggregated prefilling)功能设计。它利用 NIXL 库提供完全异步的发送/接收操作,实现高效的跨进程 KV 缓存传输。
关于功能兼容性的详细信息(支持的模型架构、TP 配置以及功能交互),请参阅 NixlConnector 兼容性矩阵。
先决条件¶
安装¶
安装 NIXL 库:在 Nvidia 平台上快速启动可运行 uv pip install nixl。
- 更多安装说明请参考 NIXL 官方仓库
- 指定的 NIXL 所需版本可在 requirements/kv_connectors.txt 及其他相关配置文件中找到
对于 ROCm 平台, 基础 ROCm Docker 文件 中已经包含了 RIXL 和 ucx。
- 更多信息请参考 RIXL 官方仓库
- RIXL 的支持库可以在 requirements/kv_connectors_rocm.txt 中找到
- 未来我们可能会从 Docker 镜像文件中移除 RIXL,届时用户将能够通过预编译的二进制包进行安装
对于非 CUDA 平台,请按照以下说明从源码安装带有 UCX 的 nixl。
传输配置¶
NixlConnector 使用 NIXL 库进行底层通信,支持多种传输后端。UCX (Unified Communication X) 是 NIXL 使用的主要默认传输库。配置传输环境变量:
# Example UCX configuration, adjust according to your environment
export UCX_TLS=all # or specify specific transports like "rc,ud,sm,^cuda_ipc" ..etc
export UCX_NET_DEVICES=all # or specify network devices like "mlx5_0:1,mlx5_1:1"
提示
当使用 UCX 作为传输后端时,NCCL 环境变量(如 NCCL_IB_HCA, NCCL_SOCKET_IFNAME)对 NixlConnector 不适用,因此请配置 UCX 专属的环境变量,而非 NCCL 变量。
选择 NIXL 传输后端(插件)¶
NixlConnector 可以使用不同的 NIXL 传输后端(插件)。默认情况下,NixlConnector 使用 UCX 作为传输后端。
要选择其他后端,请在 --kv-transfer-config 中设置 kv_connector_extra_config.backends。
示例:使用 LIBFABRIC 后端¶
vllm serve <MODEL> \
--kv-transfer-config '{
"kv_connector":"NixlConnector",
"kv_role":"kv_both",
"kv_connector_extra_config":{"backends":["LIBFABRIC"]}
}'
你也可以使用点号参数分别传递 JSON 键,并使用 + 追加列表元素
vllm serve <MODEL> \
--kv-transfer-config.kv_connector NixlConnector \
--kv-transfer-config.kv_role kv_both \
--kv-transfer-config.kv_connector_extra_config.backends+ LIBFABRIC
注意
后端的可用性取决于 NIXL 的构建方式以及环境中存在的插件。有关可用后端和构建说明,请参考 NIXL 仓库。
基础用法(在同一主机上)¶
生产者(Prefiller)配置¶
启动一个生成 KV 缓存的 prefiller 实例
# 1st GPU as prefiller
CUDA_VISIBLE_DEVICES=0 \
UCX_NET_DEVICES=all \
VLLM_NIXL_SIDE_CHANNEL_PORT=5600 \
vllm serve Qwen/Qwen3-0.6B \
--port 8100 \
--enforce-eager \
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_both","kv_load_failure_policy":"fail"}'
消费者(Decoder)配置¶
启动一个消耗 KV 缓存的 decoder 实例
# 2nd GPU as decoder
CUDA_VISIBLE_DEVICES=1 \
UCX_NET_DEVICES=all \
VLLM_NIXL_SIDE_CHANNEL_PORT=5601 \
vllm serve Qwen/Qwen3-0.6B \
--port 8200 \
--enforce-eager \
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_both","kv_load_failure_policy":"fail"}'
代理服务器¶
使用代理服务器在 prefiller 和 decoder 之间路由请求
python tests/v1/kv_connector/nixl_integration/toy_proxy_server.py \
--port 8192 \
--prefiller-hosts localhost \
--prefiller-ports 8100 \
--decoder-hosts localhost \
--decoder-ports 8200
环境变量¶
-
VLLM_NIXL_SIDE_CHANNEL_PORT:用于 NIXL 握手通信的端口- 默认值:5600
- Prefiller 和 Decoder 实例均需配置
- 每个 vLLM worker 在其主机上需要一个唯一的端口;在不同主机上使用相同的端口号是没有问题的
- 对于 TP/DP 部署,节点上每个 worker 的端口计算方式为:base_port + dp_rank(例如:当
--data-parallel-size=2且 base_port=5600 时,该节点上的 dp_rank 0..1 分别使用端口 5600 和 5601)。 - 用于 prefiller 和 decoder 之间的初始 NIXL 握手
-
VLLM_NIXL_SIDE_CHANNEL_HOST:用于侧信道通信的主机地址- 默认值:"localhost"
- 当 prefiller 和 decoder 位于不同机器时进行设置
- 连接信息通过 KVTransferParams 从 prefiller 传递给 decoder 以进行握手
-
VLLM_NIXL_ABORT_REQUEST_TIMEOUT:自动释放特定请求的 prefiller KV 缓存的超时时间(秒)。(可选)- 默认值:480
- 如果请求被中止且 decoder 尚未通过 nixl 通道读取 KV 缓存块,则 prefill 实例将在超时后释放其 KV 缓存块,以避免无限期占用。
多实例设置¶
不同机器上的多个 Prefiller 实例¶
# Prefiller 1 on Machine A (example IP: ${IP1})
VLLM_NIXL_SIDE_CHANNEL_HOST=${IP1} \
VLLM_NIXL_SIDE_CHANNEL_PORT=5600 \
UCX_NET_DEVICES=all \
vllm serve Qwen/Qwen3-0.6B --port 8000 \
--tensor-parallel-size 8 \
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_producer","kv_load_failure_policy":"fail"}'
# Prefiller 2 on Machine B (example IP: ${IP2})
VLLM_NIXL_SIDE_CHANNEL_HOST=${IP2} \
VLLM_NIXL_SIDE_CHANNEL_PORT=5600 \
UCX_NET_DEVICES=all \
vllm serve Qwen/Qwen3-0.6B --port 8000 \
--tensor-parallel-size 8 \
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_producer","kv_load_failure_policy":"fail"}'
不同机器上的多个 Decoder 实例¶
# Decoder 1 on Machine C (example IP: ${IP3})
VLLM_NIXL_SIDE_CHANNEL_HOST=${IP3} \
VLLM_NIXL_SIDE_CHANNEL_PORT=5600 \
UCX_NET_DEVICES=all \
vllm serve Qwen/Qwen3-0.6B --port 8000 \
--tensor-parallel-size 8 \
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_consumer","kv_load_failure_policy":"fail"}'
# Decoder 2 on Machine D (example IP: ${IP4})
VLLM_NIXL_SIDE_CHANNEL_HOST=${IP4} \
VLLM_NIXL_SIDE_CHANNEL_PORT=5600 \
UCX_NET_DEVICES=all \
vllm serve Qwen/Qwen3-0.6B --port 8000 \
--tensor-parallel-size 8 \
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_consumer","kv_load_failure_policy":"fail"}'
针对多实例的代理¶
python tests/v1/kv_connector/nixl_integration/toy_proxy_server.py \
--port 8192 \
--prefiller-hosts ${IP1} ${IP2} \
--prefiller-ports 8000 8000 \
--decoder-hosts ${IP3} ${IP4} \
--decoder-ports 8000 8000
对于多主机 DP 部署,仅需提供头部(head)实例的主机名/端口。
KV 角色选项¶
- kv_producer:用于生成 KV 缓存的 prefiller 实例
- kv_consumer:用于从 prefiller 消耗 KV 缓存的 decoder 实例
- kv_both:启用对称功能,使连接器既可以充当生产者也可以充当消费者。这为实验性设置以及角色区分不预先设定的场景提供了灵活性。
提示
NixlConnector 目前不区分 kv_role;实际的 prefiller/decoder 角色由上层代理确定(例如使用 --prefiller-hosts 和 --decoder-hosts 的 toy_proxy_server.py)。因此,--kv-transfer-config 中的 kv_role 实际上是一个占位符,不会影响 NixlConnector 的行为。
KV 加载失败策略¶
kv_load_failure_policy 设置控制当 decoder 实例从 prefiller 实例加载 KV 缓存块失败时,系统如何处理。
- fail(默认):KV 加载失败时,立即以错误终止请求。这通过避免在解码实例上重新计算预填充工作,防止性能下降。
- recompute:在解码实例本地重新计算失败的块。这可能会导致解码实例出现性能抖动(jitter),因为预定的预填充任务会延迟并干扰其他解码工作。此外,解码实例通常配置有低延迟优化。
警告
在生产部署中使用 kv_load_failure_policy="recompute" 可能会导致性能下降。当 KV 加载失败时,解码实例将以针对解码优化的配置执行预填充工作,这是低效的,且违背了分离式预填充的初衷。这还会增加其他正在进行的解码请求的尾部延迟。
实验性功能¶
异构 KV 布局支持¶
支持的使用场景:通过实验性配置,实现以 'HND' 格式预填充并以 'NHD' 格式解码
跨层块(Cross layers blocks)¶
默认情况下,此功能被禁用。在支持此功能的注意力机制后端上,每个逻辑块在物理内存中是连续的。这减少了需要传输的缓冲区数量。若要启用此功能:
示例脚本/代码¶
请参考 vLLM 仓库中的这些示例脚本