vLLM 用 NIXL EP 实现 Elastic EP 近零停机扩缩容
Achieving near-zero-downtime scaling in Elastic Expert Parallelism
vLLM 通过异步准备和 NIXL EP 通信库,把 Elastic EP 扩缩容时的服务中断降到近零。在 DeepSeek V4 Pro 的 GB200 基准中,从 16 扩到 20 GPU 的停机时间由 99.62 秒降至 0.82 秒,缩回 16 GPU 由 56.25 秒降至 1.96 秒。
原文给出了扩容停机从近百秒降到 0.82 秒的实测对比,可据此判断在线推理弹性伸缩的工程代价。
传统上,要在 vLLM 服务中改变 GPU 数量,需要增加或移除整个模型副本,或者以不同的 GPU 数量重启引擎。随着模型规模增大,每个副本需要更多 GPU,因此按副本扩缩容时,GPU 的增减幅度也越来越大。将 DeepSeek V4 Pro 从 16 块 GB200 GPU 扩展到 20 块时,重启 vLLM 会导致服务中断 197 秒(详见性能部分),这些昂贵的 GPU 在此期间被分配却无法生成 token。
在我们的第一篇 Elastic EP 文章中,我们展示了 vLLM 如何在不重启的情况下,从运行中的 DEP 部署(数据并行注意力 + 专家并行 MoE)中增加或移除 GPU。虽然我们避免了重启,但在整个重配置过程中服务仍然中断,因为我们需要初始化新 worker、准备扩展后的通信组、加载模型权重,并重复内核预热和 CUDA 图捕获。在 DeepSeek V4 Pro 基准测试中,从 16 块扩展到 20 块 GPU 时暂停持续了 100 秒,缩回 16 块 GPU 时暂停了 56 秒(完整细节见性能部分)。
在本文中,我们介绍异步准备和 NIXL EP 如何实现近乎零停机的 Elastic EP 重配置。在同一基准测试中,我们将停机时间缩短至从 16 块扩展到 20 块 GPU 时 0.82 秒,缩回 16 块 GPU 时 1.96 秒,使我们几乎可以在不影响服务性能的情况下进行扩缩容。
将拓扑准备与服务重叠执行
我们将 vLLM 的重配置流程重组为两个阶段:后台准备和短暂的提交。现有 worker 使用独立的后台线程来准备并预热目标通信、传输模型权重,并与加入的 worker 同步执行相关信息(如自动调优结果),同时继续使用当前的通信组和 CUDA 图处理请求。与此同时,加入的 worker 进行初始化、接收模型权重,并准备其通信和 GPU 执行。在提交阶段,vLLM 短暂暂停调度器,激活已准备好的拓扑,然后恢复服务。这些改动已在异步准备和准备/提交优化中引入。
准备阶段涵盖四项主要任务:
- 初始化加入的 worker。 启动其进程,并为模型和执行分配存储空间。
- 准备通信。 建立目标通信组并扩展 EP 通信器。
- 传输模型权重。 通过 NVLink 或 RDMA 将所需权重从现有 worker 传输到加入的 worker。
- 准备执行。 在加入的 worker 上完成所需的编译、内核预热、调优设置和 CUDA 图构建。
提交阶段之后,异步专家并行负载均衡(EPLB)允许新 worker 开始处理注意力,而现有 worker 处理专家计算。随后 EPLB 在后台将专家重新分布到扩展后的组中。
主要挑战在于准备通信和 GPU 执行时,不涉及也不干扰正在处理请求的 worker。
原地扩展 EP 通信
在 NIXL EP 之前,vLLM 中可用的 EP 通信后端使用固定成员关系:每个实例都是为特定的一组 rank 创建的。添加或移除 rank 需要创建新实例。即使该实例可以在后台创建,仍然存在两个问题。
第一,旧实例和新实例需要单独的通信缓冲区和其他资源,包括内存注册、IPC 句柄和 RDMA 队列对(QP)。保持两个实例同时存活会增加通信内存使用量,并且需要重复设置,而不是复用现有资源。
第二,切换 EP 通信器会改变 EP 通信内核所使用的缓冲区和通信状态。这会使先前捕获的 CUDA 图失效,必须在恢复服务之前重新捕获。这需要为所有保留的 worker 在许多批次形状上重复预热和图构建。在我们的 DeepSeek V4 Pro 基准测试中,即使采用异步准备,在提交阶段执行预热和图重新捕获仍导致服务暂停:扩容期间暂停 58 秒,缩容期间暂停 44 秒。
为了解决这些问题,我们设计了 NIXL EP,这是一个专为 Elastic EP 定制的 EP 通信库。它就地添加或移除 rank,复用相同的 NIXL agent、缓冲区和连接。新 peer 可以在现有 worker 继续服务的同时进行连接,并且只有加入的 peer 需要新的连接和注册。NIXL EP 还使已捕获的 EP dispatch 和 combine 条目在重配置期间保持有效,从而允许保留的 worker 复用其现有的 CUDA 图。
在准备阶段,vLLM 的后台线程连接加入的 peer,但不激活它们。随后,提交阶段激活已准备好的 peer,而不替换通信器。

图 1. 连接并激活新的 EP peer。绿色 rank 为活动状态;灰色 rank 已连接但被屏蔽。在提交阶段,新 peer 被激活,而不替换 agent 或缓冲区。
vLLM 仍会为目标拓扑创建新的 DP 协调组和 EPLB 组,但它们的通信在已捕获的模型前向传播之外运行,因此切换到它们不会使 CUDA 图失效。
在现有 worker 上保留 CUDA 图
CUDA 图记录 GPU 操作,使 vLLM 能够重放前向传播,而无需从 CPU 重复启动每个操作。捕获的内核节点包括其启动配置和参数值,包括指向输入和输出张量的指针。内存内容可以在重放之间变化,但记录的指针必须保持有效。这些要求是 CUDA 图执行契约 的一部分。
vLLM 为不同的批次形状和执行模式捕获单独的图,并在每次捕获之前运行预热前向传播。
保留已捕获的 CUDA 图不仅仅需要保持通信器对象存活。NIXL EP 还使内核启动配置、图可见的通信参数以及输入和输出张量地址在重配置期间保持稳定。其内核从可原地更新的设备状态中读取活动组成员关系。
我们还修改了 vLLM,使捕获的参数、启动配置以及周边计算内核的输入和输出张量地址在重新配置期间保持稳定:
- 我们复用保留 worker 的 fused-MoE 执行对象,而不是为不同的活跃 EP 规模重新构建它们。
- 我们保持图可见工作区和 dispatch 输出的地址与布局在重新配置期间稳定,以便已捕获的专家内核可以继续使用它们。dispatch 输出同时作为专家计算的输入。如果它们的地址或布局随 EP 规模变化,已捕获的专家内核仍会使用旧的指针和偏移量。
- 我们保留专家路由张量的底层存储,并就地更新映射。这使 EPLB 能够更改映射内容,而无需移动已捕获内核所使用的张量。
综合这些改动,保留 worker 在扩容和缩容后都能复用其现有的 CUDA 图。
独立准备加入的 worker
现有 worker 有需要保留的图。加入的 worker 则没有。
加入的 worker 通常通过运行带有 EP dispatch 和 combine 的模型前向来准备,并与其他 worker 交换批次信息。这些步骤需要其他 worker 参与,但现有 worker 已经在当前拓扑上处理真实请求。
NIXL EP 允许每个加入的 worker 在预热和图准备期间临时屏蔽所有远程 EP 对等节点。只有该 worker 的本地 rank 在 EP 通信中处于活跃状态。我们还修改了 vLLM,使这些准备过程不再等待来自其他 worker 的 DP 批次信息。这使得加入的 worker 可以运行其虚拟批次并捕获 CUDA 图,而无需现有 worker 参与。

图 2。绿色 rank 在 EP 通信中处于活跃状态;灰色 rank 被屏蔽。现有 worker 一起提供服务,而每个加入的 worker 在准备期间屏蔽所有远程 EP 对等节点。
捕获完成后,NIXL EP 可以重新激活对等节点而不会使图失效。加入的 worker 在作为扩展组的一部分开始提供服务时,会复用其本地捕获的图。
DeepSeek V4 Pro 上的性能
本节所有实验均在 GB200 GPU 上使用 DeepSeek V4 Pro,TP=1,DP/EP 规模为 16 和 20。模型权重已以 safetensors 格式预下载到共享 Lustre 存储上,并使用默认的 --load-format auto 加载。测量使用了预热的 kernel 编译缓存(Triton、TileLang 和 FlashInfer)。
扩容和缩容耗时
下表显示了哪些阶段在服务暂停时运行,哪些阶段在现有 worker 继续提供服务时于后台运行。
| 阶段 | A:阻塞 | B:异步准备 | C:异步准备 + 图复用 |
|---|---|---|---|
| 初始化加入的 worker | 服务暂停 | 后台 | 后台 |
| 准备目标通信 | 服务暂停 | 后台 | 后台 |
| 传输模型权重 | 服务暂停 | 后台 | 后台 |
| 在加入的 worker 上预热并捕获图 | 服务暂停 | 服务暂停 | 后台 |
| 在现有 worker 上预热并捕获图 | 服务暂停 | 服务暂停 | 不需要(现有图保持有效) |
| 激活目标拓扑 | 服务暂停 | 服务暂停 | 服务暂停 |
配置 C 仅由 NIXL EP 支持。
- 停机时间:观察到的服务中断,此时进行中的请求停止推进,新请求不被接纳。
- 总时间:整个扩缩容操作的持续时间,包括准备阶段。
这两个时长分别测量。
| 指标 | A:阻塞式 | B:异步准备 | C:异步准备 + 计算图复用 |
|---|---|---|---|
| 16 到 20 个 GPU:停机时间 | 99.62 s | 58.04 s | 0.82 s |
| 20 到 16 个 GPU:停机时间 | 56.25 s | 44.07 s | 1.96 s |
| 16 到 20 个 GPU:总时间 | 99.72 s | 97.27 s | 92.34 s |
| 20 到 16 个 GPU:总时间 | 56.21 s | 51.46 s | 9.32 s |
所有配置均通过了数值正确性检查,包括对每个加入的 worker 的检查。
在添加 GPU 的同时维持 SLO
我们在 16 个 GPU 上部署了 DeepSeek V4 Pro,然后将传入请求速率从约每秒 8 个请求逐步提高到每秒 16 个请求。我们针对三个部署重放了相同的 11,391 个请求场景:一个保持在 16 个 GPU,一个以 20 个 GPU 重启,一个使用 Elastic EP 配合 NIXL EP 扩展到 20 个 GPU。服务级别目标(SLO)是滚动 p95 首 token 时间低于 5 秒。

图 3. 请求负载上升下的端到端服务。曲线显示 30 秒滚动 p95 结果,失败的请求被赋予 30 秒惩罚值,而非实测的 TTFT。
- Elastic EP 完成了全部 11,391 个请求,并在整个场景中始终低于 SLO。
- 在准备期间,Elastic EP 的服务性能与静态 16-GPU 部署相当,后台准备没有带来可见的性能下降。
- 扩容后,Elastic EP 的性能与恢复后的 20-GPU 部署相当,扩容后没有可见的性能下降。
试用 Elastic EP
后台准备、CUDA 计算图复用以及加入 worker 上的独立计算图捕获,现已在最新的 vLLM 和 NIXL 版本中提供。使用 pip 安装它们,即可开始使用 Elastic EP。
完整的使用示例,请参见 vLLM 的 Elastic EP 测试中的 cuda_graphs_heavy_nixl_ep 用例。该示例包含服务器配置和扩缩容 API 调用。它在发送请求的同时从两个 GPU 扩展到四个再返回,检查准备期间的服务情况以及每次调整规模前后的模型准确性。
接下来是什么
使用 Dynamo Snapshot 恢复热 worker
我们已有效解决了长时间的服务中断。下一个挑战是让新容量更快就绪。我们计划集成 Dynamo Snapshot,使加入的 worker 能够恢复已初始化的进程和 CUDA 状态,而无需重复编译、内核预热、计算图构建和其他启动工作。
目标拓扑的通信必须单独准备,因为它无法从快照中恢复。从检查点存储恢复大型模型权重可能主导恢复时间,因此我们计划保留 Elastic EP 从现有 worker 进行 GPU 到 GPU 权重传输的方式。
使用 NIXL EP 实现最先进的 EP 通信
我们的目标是在 NIXL EP 上实现最先进的 dispatch 和 combine 性能,同时保持对 Elastic EP 和容错的完整支持。即将到来的 NIXL EP 性能更新是迈向该目标的下一步(参见 NIXL EP 路线图 RFC)。
将 Elastic EP 连接到 Dynamo 和 llm-d 编排
引擎层面的能力已经就绪,下一步是在编排器自动扩缩器中利用 Elastic EP。vLLM、Dynamo 和 llm-d 社区已经在推进这一集成工作。
这些工作包括 vLLM 的外部负载均衡器工作 和 Dynamo 的 Elastic EP 提案。
如果你在大规模运行推理,我们鼓励你尝试 Elastic EP,并分享你的工作负载和运维需求。如果你在构建推理基础设施,我们欢迎你为 vLLM Elastic EP 和 NIXL EP 做贡献。让我们把 Elastic EP 投入生产运行。
致谢
- 感谢 Red Hat 的 Tyler Michael Smith 和 Sage Moore 在整个工作过程中提供的宝贵反馈和细致审阅。
- 感谢 NVIDIA 的 Linoy Geva 在准备期间所做的服务性能工作。
- 感谢整个 NIXL 团队在 NIXL EP 上的努力。
- 感谢 Tzu-Ling Kan、Julien Mancuso 以及整个 Dynamo 团队为在 Dynamo 中支持 Elastic EP 所做的努力。
来源:vLLM Blog · vllm.ai