跳到内容

NixlConnector 使用指南

NixlConnector 是一个高性能 KV 缓存传输连接器,专为 vLLM 的分离式预填充(disaggregated prefilling)功能设计。它利用 NIXL 库提供完全异步的发送/接收操作,实现高效的跨进程 KV 缓存传输。

关于功能兼容性的详细信息(支持的模型架构、TP 配置以及功能交互),请参阅 NixlConnector 兼容性矩阵

先决条件

安装

安装 NIXL 库:在 Nvidia 平台上快速启动可运行 uv pip install nixl

对于 ROCm 平台, 基础 ROCm Docker 文件 中已经包含了 RIXL 和 ucx。

对于非 CUDA 平台,请按照以下说明从源码安装带有 UCX 的 nixl。

python tools/install_nixl_from_source_ubuntu.py

传输配置

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-hoststoy_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' 格式解码

--kv-transfer-config '{..., "enable_permute_local_kv":"True"}'

跨层块(Cross layers blocks)

默认情况下,此功能被禁用。在支持此功能的注意力机制后端上,每个逻辑块在物理内存中是连续的。这减少了需要传输的缓冲区数量。若要启用此功能:

--kv-transfer-config '{..., "kv_connector_extra_config": {"enable_cross_layers_blocks": "True"}}'

示例脚本/代码

请参考 vLLM 仓库中的这些示例脚本