vLLM 中的弹性专家并行
Elastic Expert Parallelism in vLLM
vLLM 实现了弹性专家并行(Elastic EP),允许混合专家(MoE)模型在运行时通过添加或移除数据并行(DP)worker 来动态调整部署规模,无需重启服务器。该功能通过 `POST /scale_elastic_ep` API 触发,支持扩容和缩容,流程包括新 engine-core 初始化、备用通信组创建、专家映射与权重传输、拓扑切换及 EPLB 专家重新分配。Elastic EP 使用两阶段屏障协调跨 DP rank 的异步操作,并支持 NIXL EP 后端以减少重新初始化开销。该功能是 vLLM 容错方向(RFC #30112)的核心构建块,为故障检测、缩容移除故障 rank 及扩容恢复提供运行时重新配置路径。当前实现限制为 `tensor_parallel_size=1`、单 API 服务器且无 DBO,依赖 Ray DP 后端。
专家并行(Expert Parallelism,EP)是服务于混合专家(Mixture-of-Experts,MoE)模型以实现高吞吐量的关键技术。广泛的 EP 部署(即 EP 跨越多个 worker)能最大化 KV 缓存容量,从而实现极高的并发性或极长的上下文。这对于需要长上下文和高吞吐量的强化学习工作负载,以及多轮对话可能拉长上下文长度的 agentic 工作负载尤为重要。
在 vLLM 中,与许多其他推理框架一样,EP 是静态的:一旦部署启动,其服务容量就固定了。如果请求量超过该容量,vLLM 无法扩容以满足需求。如果需求下降,它也无法缩容以减少 GPU 使用和成本。唯一可行的选择是使用新配置完全重启,这很慢,并且可能丢弃大量流量。
弹性专家并行(Elastic EP)改变了这一点。它允许 vLLM 在运行时重新配置 worker 数量,因此 MoE 部署可以根据需求变化进行扩容或缩容,且对服务的干扰最小。
Elastic EP 通过添加或移除数据并行(Data-Parallel,DP)worker 来实现伸缩。在 vLLM 中,这会改变共享的专家并行(EP)组的大小以及专家在 worker 间的分布方式,我们将在背景部分解释。只需一个 API 调用即可:
curl -X POST http://localhost:8000/scale_elastic_ep \
-H "Content-Type: application/json" \
-d '{"new_data_parallel_size": 8}'
此 API 调用会将正在运行的部署从其当前的 DP 大小调整为 8 个 worker。
本文描述了 vLLM 中的 Elastic EP(RFC #20323,PR #34861),包括扩容和缩容流程、vLLM 如何协调重新配置与正在执行的请求、该功能如何与 EPLB 和 EP 通信后端交互,以及为什么这项工作与 vLLM 新兴的容错方向高度相关。本文还讨论了 NIXL EP(PR #35627)作为一种后端,其通信模型与弹性重新配置和容错特别相关。
面向运维人员的 TL;DR:
- Elastic EP 允许 vLLM 通过更改 DP 大小在运行时对 MoE 部署进行扩容或缩容,而无需重启服务器。
- 您通过
POST /scale_elastic_ep触发大小调整;vLLM 会重新配置实时拓扑并按需重新分配专家。- 此运行时重新配置路径是 vLLM 中容错服务的核心构建块。
- NIXL EP 可以显著减少伸缩事件期间的重新初始化工作,并提供 EP 侧的故障检测、报告和恢复能力。
背景:专家并行与 DP Attention
在 MoE 模型中,attention 层仍然是密集的,而大多数前馈层被替换为稀疏的专家层,这些层将每个 token 路由到选定的专家集合。在深入探讨弹性伸缩之前,了解 Elastic EP 所依赖的两种并行策略会有所帮助。
数据并行(DP)Attention 使用请求级并行:每个 engine-core 处理不同的请求分片,并维护自己的 KV 缓存和调度器。这在 MLA 等架构中尤其有用,因为在这些架构中,张量并行(TP)会在 GPU 间重复 KV 缓存,浪费内存并限制批处理大小。
专家并行(EP) 用于专家层。专家不是跨 GPU 分片,而是分布在不同 GPU 上,token 仅被分发到拥有所选专家的 GPU。
在 vLLM 中,attention 在每个 DP worker 上独立运行,而专家层在这些 worker 之间共享一个 EP 组(EP 组大小为 DP x TP)。Elastic EP 在运行时更改 DP worker 的数量,从而相应地缩放 EP 组并跨组重新分配专家。
挑战:需要更改哪些状态?
在运行时伸缩 DP 不仅仅是启动或终止进程的问题。EP 大小的变化会使多个运行时状态失效:
- 分布式通信组。 EP、DP 和 world 组都嵌入了固定的 rank 集合。
- 专家分配。 专家到 rank 的映射在 EP 大小改变时会发生变化。
- 模型权重。 新的 rank 需要模型权重,而现有的 rank 在重新分配后可能需要更新的专家权重。
- CUDA graphs 和编译状态。 CUDA graph 捕获和
torch.compile都针对在拓扑变化时会改变的假设进行了特化。
因此,实现将伸缩视为一个协调的状态机。每个阶段都有明确的同步点,并且这些同步点必须与模型前向执行安全共存。
扩容流程
从 DP=N 扩容到 DP=M(其中 M > N)比缩容更复杂,因为需要将新的 rank 引入正在运行的部署。
1. 触发与请求处理
操作从 /scale_elastic_ep 开始。如果设置了 VLLM_ELASTIC_EP_DRAIN_REQUESTS=1,vLLM 首先会等待正在处理的请求排空,最多等待 drain_timeout 秒(默认 120 秒)。否则,立即进行伸缩。
2. 新 Engine Core 初始化
启动新的 engine-core worker 依赖于 Ray DP 后端。在扩容期间,Ray DP 后端会在当前可用的 GPU 上启动目标 DP 大小所需的额外 DP worker。新的 rank 接收当前的专家映射,并使用占位权重初始化模型。然后它们等待后续的传输和重新配置阶段,以将它们带入活动拓扑。
就绪状态分两个阶段协调:一个信号允许现有 rank 创建备用组,稍后的信号允许开始权重传输。
3. 备用通信组
一个关键的设计选择是,vLLM 不会立即拆除活动的通信组。相反,现有的 rank 首先创建跨越目标 rank 集合的备用组。这些组使用 StatelessGroupCoordinator 创建,它独立于 PyTorch 的全局 WORLD 状态。
这使得在切换之前准备新配置成为可能,同时旧配置仍可以执行前向传播。
使用 nixl_ep,这种转换可以是增量的:vLLM 无需拆除并重新创建所有 EP 侧连接,而是可以通过 NIXL EP 的 connect_ranks() / disconnect_ranks() API 添加或移除 rank,同时保持现有连接不受影响。
4. 专家映射与权重传输
一旦备用组存在,我们使用它们将当前的专家映射广播出去,并将非专家权重从现有 rank 传输到新 rank,传输工作尽可能均匀地分布在现有 rank 上。Elastic EP 复用了 EPLB 用于专家权重移动的相同 GPU 到 GPU 发送/接收路径,但将其扩展到 attention 层、归一化层、embedding 层和其他非专家权重,使用可用的高速互连,例如节点内的 NVLink 或跨节点的 RDMA。
专家权重在此阶段不会被移动。它们将在新拓扑激活后由 EPLB 传输。在转换期间,常规的 EPLB 活动会暂停,以免干扰重新配置。
5. 切换
切换是所有 rank 停止使用旧拓扑并开始使用新拓扑的时刻。在此阶段,vLLM 会:
- 释放 CUDA graphs 并重置
torch.compile状态。 - 将备用组提升为活动的 EP、DP 和 world 组。
- 销毁旧组。
- 为新的 EP 大小重新配置 MoE 模块。
- 重新预热模型,使 CUDA graphs 和编译路径与新设置匹配。
引擎协调状态,例如运行标志、wave 计数器和步骤计数器,会在新的 DP 组中同步,以便每个 rank 从一致的点恢复。
此时,新的 rank 已成为活动 DP 组的一部分,可以参与前向传播并运行 attention,但它们尚未拥有专家。专家所有权会在后续的 EPLB 重新洗牌中更新。
6. EPLB 重新洗牌
新拓扑激活后,EPLB 会在所有 M 个 rank 之间重新分配专家。这会更新专家映射并执行新布局所需的专家权重移动。重新洗牌完成后,常规的 EPLB 操作恢复。
缩容流程
从 DP=M 缩容到 DP=N 遵循与扩容相同的一般模式,但有一个重要区别:EPLB 重新洗牌必须首先发生。即将被移除的 rank 可能仍然拥有专家权重,因此所有 M 个 engine-core 首先参与一次重新洗牌,将专家整合到 N 个幸存的 rank 上,并将任何必要的专家权重从即将离开的 rank 迁移出去。
跨 DP Rank 协调重新配置步骤
一个微妙的问题是,DP engine-core 是异步运行的,因此它们可能在不同时间收到重新配置通知。当某些 rank 到达下一个 Elastic EP 阶段时,其他 rank 可能已经开始多执行一个前向步骤。如果较早的 rank 立即继续,组将在重新配置和前向执行之间分裂,从而导致部署死锁。
Elastic EP 通过两阶段屏障来处理这个问题。第一个屏障使用超时:如果它没有及时完成,到达的 rank 推断某些对等方已经进入了另一个引擎步骤,因此它们也返回引擎循环再进行一次迭代,而不是单独继续。在下一次迭代中,一旦所有 rank 到达相同的边界,第二个屏障(没有超时路径)允许它们一起进入下一阶段。
通往容错之路
Elastic EP 是容错的核心构建块,因为它为 vLLM 提供了故障后所需的运行时重新配置路径。如果一个 rank 宕机,Elastic EP 提供了必要的缩容和扩容路径来移除该 rank、重新分配其专家,并在之后添加替代容量,而无需重启整个部署。这是 RFC #30112 中讨论的更广泛容错方向的一部分。
在高层面上,恢复流程如下所示:
- 检测 通过健康检查或后端特定的故障信号来检测故障。
- 缩容 以移除故障 rank 并重新分配其专家。
- 扩容 一旦替代容量可用,再次扩容。
NIXL EP 在这里也很相关,因为它可以检测、报告和恢复 EP 侧的故障,以及在容量再次可用时重新连接替代 rank。
后续步骤
Elastic EP 已经提供了核心的运行时重新配置路径,但当前的实现仍然有相当特定的范围和一些明显的后续领域:
- 支持更丰富的并行配置。 这包括
tensor_parallel_size>1和其他并行配置。 - 支持更多服务特性。 当前实现将
api_server_count限制为 1,并且尚不支持 DBO 或 MoE draft/drafter 模型。 - 减少重新配置窗口。 在重叠、预热成本、CUDA graph 重新捕获以及重用先前准备的状态方面仍有工作要做。
- 将 Elastic EP 连接到自动伸缩策略。 运行时控制平面已就绪;策略和编排是单独的工作(Dynamo, llm-d)。
- 支持额外的 DP 后端。 伸缩操作目前依赖于 Ray DP 后端。
入门指南
启用 Elastic EP 启动
下面的示例使用 DeepSeek-V2-Lite-Chat 作为小型 MoE 示例。当前实现针对 tensor_parallel_size=1、一个 API 服务器且没有 DBO 的 Ray DP 部署。
vllm serve deepseek-ai/DeepSeek-V2-Lite-Chat \
--trust-remote-code \
--tensor-parallel-size 1 \
--data-parallel-size 2 \
--data-parallel-backend ray \
--api-server-count 1 \
--enable-expert-parallel \
--enable-elastic-ep \
--enable-eplb \
--eplb-config.num_redundant_experts 0 \
--all2all-backend allgather_reducescatter \
--gpu-memory-utilization 0.8
运行时扩容
使用 Ray DP 后端,添加容量可以简单到将另一个节点加入 Ray 集群;一旦 Ray 看到新的 GPU,Elastic EP 就可以在运行时将部署扩展到它们上面。
例如,在一个新的 worker 节点上:
ray start --address="${HEAD_NODE_IP}:6379"
curl -X POST http://localhost:8000/scale_elastic_ep \
-H "Content-Type: application/json" \
-d '{"new_data_parallel_size": 16}'
缩容
curl -X POST http://localhost:8000/scale_elastic_ep \
-H "Content-Type: application/json" \
-d '{"new_data_parallel_size": 8}'
使用 NIXL EP 作为通信后端
如果您想将 NIXL EP 与 Elastic EP 一起使用:
uv pip install nixl
vllm serve deepseek-ai/DeepSeek-V2-Lite-Chat \
--trust-remote-code \
--tensor-parallel-size 1 \
--data-parallel-size 2 \
--data-parallel-backend ray \
--api-server-count 1 \
--enable-expert-parallel \
--enable-elastic-ep \
--enable-eplb \
--all2all-backend nixl_ep
有关安装详细信息和传输配置,请参阅 NIXL 仓库。
参考文献
- RFC #20323: Elastic Expert Parallelism
- PR #34861: [1/N] Elastic EP Milestone 2
- PR #35627: [2/N] Elastic EP Milestone 2: Integrating NIXL-EP
- RFC #30112: Fault-Tolerant Expert Parallelism
- RFC #16037: Data Parallel Attention and Expert Parallel MoEs
致谢
感谢所有为将 Elastic EP 引入 vLLM 做出贡献的人。
- Sky Computing: Yongji Wu
- NVIDIA: Itay Alroy, Moein Khazraee, Omri Kahalon, Tzu-Ling Kan, Ron Tourgeman
- Red Hat: Tyler Michael Smith
- Anyscale: Rui Qiao
- 更广泛的 vLLM 社区