vLLM 基于推送的 NIXL KV 连接器:分离推理的 TTFT 最高提升 3 倍
vLLM 为预填充-解码(P-D)分离推理新增了基于推送的 NIXL KV 连接器,将传输协调和设置从首令牌关键路径中移除。在使用 AWS EFA 连接的 Amazon EC2 P5en 实例上的 1P1D 部署中,针对 Qwen3-32B 的基准测试显示,与默认的拉取模式相比,推送模式的首令牌时间(TTFT)最高提升 3 倍,每输出令牌时间(TPOT)最高提升 30%。
推送连接器解决了什么问题
预填充-解码分离将预填充和解码分别运行在不同的引擎实例上,使每个阶段能够独立扩展和优化,从而提高资源利用率、吞吐量和负载下的延迟表现。代价是 KV 缓存必须在令牌生成开始前从预填充实例传输到解码实例,这使得 KV 传输直接位于 TTFT 关键路径上。
vLLM 通过 NVIDIA 推理传输库(NIXL)连接器执行此传输,该连接器在支持 RDMA 的互连(如 AWS 弹性结构适配器(EFA))上移动 KV 块。在支持的实例类型上,EFA 支持 GPUDirect RDMA 和 Neuron Direct RDMA,因此 NIXL 可以直接在 GPU 或 Trainium 设备内存之间传输 KV 块,而无需通过主机内存暂存。
默认的 NIXL 连接器模式是基于拉取的。预填充实例完成提示 KV 缓存计算后,路由器将源元数据(包括预填充块 ID)中继到解码实例。解码实例随后分配目标块、准备 NIXL 传输,并启动 NIXL READ 以从预填充实例拉取 KV 块。由于这些协调和设置步骤在预填充之后、解码开始之前顺序执行,它们延长了 TTFT 关键路径。
基于推送的 KV 传输如何工作
基于推送的传输改善 TTFT 和解码吞吐量的两个原因在 vLLM 帖子中说明:
- 它消除了拉取模型的串行化,通过重叠生产者和消费者工作。解码实例在生产者在计算 KV 时预先注册其目标块。传输在生产者块就绪后立即开始,而不是等待消费者端标识符发现往返,从而将该往返从首令牌路径中移除。
- 它将传输设置时间从解码实例中移出。 准备 NIXL 描述符和提交传输在预填充端和后台线程上运行,因此解码实例在其延迟关键的令牌生成阶段不会花费这些周期。
净效果是更低的 TTFT 和更高的输出令牌吞吐量。
推送连接器协调三个参与者:解码实例(预先注册其目标块)、预填充实例(匹配每个请求并发起传输)、以及一个专门的后台线程(在引擎的前向循环之外执行 KV 写入)。
三步协议
1. 注册(解码端)。 当解码实例为需要远程预填充的请求分配本地块时,它准备一个注册,描述预填充实例应写入 KV 的位置:其自身身份和刚保留的块位置。在同一引擎步骤中,Worker 通过 NIXL 通知将此注册传输到预填充实例。由于注册发生在分配时,连接器在预填充实例完成预填充之前就知道目标块。
2. 会合(预填充端)。 来自解码器的注册和生产者的预填充完成可能以任意顺序到达,连接器处理这两种情况。如果注册先到达,生产者将其保留,直到自身预填充完成。如果预填充先完成,生产者保留请求的块,直到注册到达。无论哪个事件后到达都会触发传输。连接器通过标识符匹配请求,匹配过程考虑重新发出的请求,正确关联被抢占或重试的请求。
3. 传输(预填充端)。 请求匹配后,生产者建立到解码实例的连接(如果尚不存在),并发出 NIXL WRITE,直接将 KV 块复制到解码器注册的内存中,寻址每个目标张量并行秩。生产者和消费者可能使用不同的内部块布局;每侧在传输时将块位置映射到其自身物理布局,允许每侧使用不同的块大小。每个 WRITE 携带完成通知,NIXL 在数据到达后将其传递给解码实例。解码器计数这些通知(每个向其写入的生产者秩一个),并且仅在所有预期通知到达后才将 KV 视为已接收,此时请求继续解码。
线程模型
推送连接器通过在每个预填充 Worker 上使用专门的后台传输线程,将模型执行与 KV 传输准备分离。在请求开始时,解码主循环分配其目标 KV 块并向预填充实例注册它们,而预填充主循环计算提示 KV 缓存。在目标注册和提示 KV 都就绪后,预填充主循环将 KV 块交给后台线程,并快速返回模型执行。
后台线程建立或重用 NIXL 连接,将请求的 KV 块 ID 映射到内存描述符,将连续块合并为更大的传输区域,并向解码实例提交 NIXL WRITE。当 NIXL 完成传输时,它向解码实例发送完成通知,解码实例随后开始令牌生成。将描述符准备和传输提交保持在延迟关键主循环之外,可防止此每请求工作延迟模型执行。
拉取与推送:路由权衡
两种模式使用相同的 NIXL 和 EFA/RDMA 数据路径。拉取在预填充后执行元数据中继和解码端设置,而推送将解码端设置与预填充重叠,将这些操作从预填充后关键路径中移除,使解码能够更早开始。
两种模式还涉及路由权衡。拉取模式允许路由器在预填充完成后选择解码实例,为负载感知路由和服务质量管理提供更大灵活性。推送模式更早选择解码实例,使目标设置能够与预填充重叠。作为回报,在类似负载下,预填充实例可以更早释放其 KV 块,因为传输在提示 KV 和目标注册都就绪后立即开始。
性能数据
评估使用 Qwen3-32B 模型,在 1P1D 部署中使用 EFA 连接的 Amazon EC2 P5en 实例。为了隔离 P→D 传输性能,基准测试使用 --no-enable-prefix-caching 禁用前缀缓存,迫使解码节点为每个请求从预填充节点检索完整 KV 缓存。没有该设置,重叠提示可以重用解码节点的本地缓存并绕过传输,导致误导性的比较结果。
TTFT。 基准测试扫描了 1k–16k 的输入长度和 1–8 QPS 的请求速率。在低负载和短提示下,两种模式性能几乎相同。随着 QPS 和输入长度的增加,拉取模式急剧恶化,在 8 QPS 和 16k 输入时达到约 1,744 毫秒。推送模式保持在约 540 毫秒,远低于前者,约为 3 倍的降低。差距出现的原因是拉取模式在解码 Worker 上内联发布 NIXL 描述符(在其引擎循环内同步),因此该工作停顿令牌生成;推送模式将其移至后台线程,脱离关键路径。
TPOT。 在相同条件下,模式与 TTFT 相似。在轻负载下,推送和拉取接近,约为 5.6–5.8 毫秒。随着负载和输入长度增加,拉取在 4–8 QPS 和 16k 输入时爬升至约 10.4 毫秒,而推送保持在约 7 毫秒。由于推送将描述符准备和传输提交从解码 Worker 卸载,令牌生成永远不会被饿死,因此即使在高并发和长上下文下,每令牌延迟也保持平坦。
如何启用推送模式
要使用推送模式,请将预填充和解码服务器配置为使用 NixlPushConnector 而不是 NixlConnector。vLLM 帖子指出,该功能是在 AWS Trainium 实例集群(使用 EFA 连接)上构建和验证的,然后作为与加速器无关的功能贡献给 vLLM;发布的结果来自使用 EFA 的 AWS p5en(GPU)集群,表明收益同样适用于 GPU。
何时选择推送与拉取
当早期解码节点选择可接受且较低 TTFT 是优先事项时,选择基于推送的连接器。基于拉取的连接器仍然是需要双向 KV 传输或延迟解码实例选择直至预填充后以实现负载感知路由的工作负载的更好选择。vLLM 支持基于推送和拉取的 KV 连接器,允许用户选择最适合其部署的方法。
复现基准测试
参考拓扑是两个 p5en GPU 节点(预填充在 :8100,解码在 :8200)启用 EFA,外加一个较小的节点运行代理和基准测试客户端。两个 GPU 节点使用 p5en.48xlarge(8x NVIDIA H200)、Ubuntu 24.04.4 LTS 内核 6.14.0-1018-aws、NVIDIA 驱动 580.126.16(CUDA 13.0 驱动 API)、CUDA 工具包 13.0 和 EFA 安装程序 1.50.0(EFA 内核模块 3.3.0g,libfabric 2.6.0amzn1.0,rdma-core 64.0amzn0)。每个实例暴露 16 个 EFA 接口,每个 200 Gb/s,总计 3.2 Tb/s。
复现指南中的软件版本为 vllm==0.29.0 和 nixl==1.4.1。模式差异是单个配置字段:NixlConnector 用于拉取,NixlPushConnector 用于推送。解码服务器添加 --no-enable-prefix-caching 以强制从预填充完全获取 KV。基准测试脚本位于 vLLM 拉取请求 #57567 中,帖子附带 serve_pd.sh、run_sweep.sh、cleanup.sh 和 plot_push_vs_pull.py,用于启动、扫描、拆除和重新绘制图形。
关于 EFA 设备选择,LIBFABRIC 后端使用 efa 提供程序将所有 16 个 EFA 设备作为轨道打开,然后仅在与该 GPU 的 PCIe 交换机共享的 2 个轨道上注册每个 GPU 的 KV 缓存,因此每次传输都保持 PCIe 本地。未设置 NIXL 或 libfabric 设备覆盖;这是默认选择。
未来工作
vLLM 正在探索将后台 NIXL 线程模型引入拉取模式连接器,将 NIXL 设置移出关键路径,以便拉取模式工作负载也能受益于相同的优化。已打开拉取请求(#45211)以探索这一点。