SGLang推出Elastic EP扩容:MoE推理加GPU不用重启
SGLang 引入 Elastic Expert Parallelism Scaling,让 MoE 推理服务可在运行中细粒度增加 GPU,无需完整副本或重启。借助 Mooncake PG 与 NIXL,系统在 8×H100 测试中比重启更快完成扩容,并支持 CUDA graph 重捕获与 EPLB 重平衡。
线上推理服务的负载总在变,系统得在不牺牲吞吐和延迟目标的情况下调整容量。落到大型 Mixture-of-Experts (MoE) 模型上,过去主要有两条路:一是水平扩容,多加一个完整模型副本;二是垂直扩容,用更宽的 expert-parallel 拓扑重启部署。
水平扩容不打断当前服务,可代价是要再放下一整份模型。垂直扩容的增量小,能凑到目标拓扑,但分布式状态得重建、模型得重新加载、还得跑完预热。SGLang 这次给出的 Elastic EP scale-up 是第三种办法:在跑着的 MoE 部署里直接塞进新的 GPU ranks。
文中示例里,一个 20-GPU 部署既没有替换现有作业,也没有另建完整的 20-GPU 副本,而是直接加了 4 个 ranks,扩到 24 GPUs。

图 1:20→24 GPU 的示意对比。Elastic EP Scaling 是在运行中的部署上增加 4 个 ranks,并非分配另一个 20-GPU 副本,也不是整体替换作业。
核心结论
- Elastic EP scale-up 让 MoE 模型能按更细的粒度加 GPU,既不用部署完整副本,也不用重启当前服务。
max_ep_size它定义了部署可扩展到的最大 EP 拓扑。系统启动时先把元数据和通信缓冲区的容量预留出来,额外的 GPU ranks 则等到需要时才启动。- 报告给出的对比中,Elastic EP Scaling 到达首个完成请求的速度比重启快 5.3×–8.2×。
扩容机制如何复用故障恢复能力
每次 MoE forward,token activations 会被送到持有被选中 experts 的那些 ranks,expert 输出再回到源 ranks。SGLang 此前的大规模 EP 工作已经表明,expert dispatch 这条路径对高并发、长上下文服务很关键。采用 Data Parallel (DP) attention 时,每个逻辑 DP worker 各自维护调度器和 KV cache,expert layers 则跨 EP 拓扑通信。
运行时扩容直接建在 SGLang 的Elastic EP failure-recovery机制上面。两者都靠 active/inactive membership、Mooncake Process Group (Mooncake PG)admission,以及 forward 结束时的 transition hook。不同之处在于:故障恢复是把某个 rank 放回原有的 slot 和原 process groups;扩容则是激活active_ranks向量里为最大规模预留的尾部空 slot,并接纳新加入的 ranks。
这个设计受一条关键约束牵制:启动时创建的 process groups 是静态的。所以原始 ranks 和每个新加入的 group 都得保留固定的Tensor Parallel (TP)与 bootstrap groups;在它们之上,MooncakeWORLD和逻辑 EP membership 才能继续增长。

图 2:EP4→EP6 时,原始 4-rank launch group 保持不变,2 个新 ranks 被接纳进 Mooncake WORLD,同时 NIXL 的目标 peer 集合扩展。
一个逻辑部署,三层协同
1. SGLang 负责 serving control plane
SGLang 会等请求加入的 ranks,分别追踪pending_ep_size 与 effective_ep_size,在一次 forward 结束时装好目标 expert 和 DP 状态,并且要等 commit 之后才把新的 scheduler slots 露出来。
2. 弹性 membership 与同步交给 Mooncake PG
Mooncake PG 本身具备可扩展能力WORLD它负责接纳 joiners,并提供一个 barrier,覆盖现有 ranks 和新 ranks。扩容完成后,SGLang 还用 Mooncake PG 的 collectives 与 P2P 做协调。EPLB。
3. NIXL 承担 expert data plane
每次 MoE forward 中,token activations 的分发与 expert 输出的合并都由 NIXL EP 完成。SGLang 的集成放在 NIXL dispatcher 里。EP group 扩大时,NIXL 会保留已有的 peer 连接:以 EP4→EP6 为例,原始 ranks 的既有连接不动,只新增 ranks 4 和 5;新加入的 ranks 则去连接 EP6 的 peer 集合。
启动时,SGLang 会依据max_ep_size来配置 NIXL 元数据和 RDMA buffers,不过初始阶段只连 active ranks。连接是惰性建立的,所以第一次在更宽拓扑上做 dispatch 时,可能带上一部分建连开销。
max_ep_size应当设成部署预期能达到的最大拓扑。这个上限越高,active GPUs 上预留的通信缓冲区内存就越多,留给 KV cache 的内存相应越少。
运行中的 EP group 怎么变大
SGLang 的在线扩容流程分四步:
- 预留上限。Primary 通过
max_ep_size来分配元数据和通信缓冲区容量。inactive slots 既不启动进程,也不占 GPU。 - 启动 joining ranks。外部 orchestrator 负责分配 GPU、拉起新 ranks,这期间现有 EP group 照常提供服务。
- 接纳并提交。SGLang 先等完整的目标 rank 范围到齐,再扩展 Mooncake
WORLD,装上目标 active-rank、expert、DP 和 NIXL 状态,并让所有 ranks 同步。若启用了 CUDA graphs,各 ranks 会在提交新规模之前重新捕获图。完成这些之后,commit_scale()才会推进 effective size。 - 路由与重平衡。Data Parallel Controller 对外暴露新的逻辑 workers。NIXL 先执行第一次范围更宽的 expert dispatch,之后 EPLB 可以重新分配 experts。
要注意的是,joining ranks 进入 MooncakeWORLD之后,自动回滚目前还不支持;一旦 finalization 阶段失败,可能得重启部署。
扩容切换的实测结果
作者在 8×H100 上用 DeepSeek-V3-Lite FP8 把 Elastic EP Scaling 和重启方案做了对比。Elastic EP Scaling 下,新加入的 ranks 在后台初始化,现有部署继续服务;重启方案的计时从源部署被终止之前算起。
多次 Elastic 运行中,每次 transition 都成功完成,也通过了扩容后的 GSM8K 验证。图 3 给出 Elastic 的平均耗时,并与 CUDA-graph capture range 相同的重启基线作对比。
测试终点是 readiness 之后发出的短 canary 请求。Elastic readiness 以/is_scaling_elastic_epElastic readiness 的判定标准,是返回目标规模的 [[保留1]];而重启 readiness 则以 [[保留2]] 返回 HTTP 200 为准。两种方案在 canary 流量的走向上也不一样:Elastic 会把 canary 定向到新的逻辑 DP rank,重启方案则沿用 round-robin routing。serving_expanded/health_generate

图 3 统计的是从扩容或重启请求发起,到目标拓扑上首个请求完成所花的时间。图中 Elastic 柱状图取多次运行的均值,restart 柱状图作为对比基线。CUDA-graph 那几行覆盖了 batch 16 以内的 5 个 full-decode shapes。
拓扑切换期间 token delivery 会暂停。图 3 的统计范围从 scale request 一直算到扩展部署上首个请求完成,第一次使用时可能出现的连接建立开销也计入其中。整体看下来,Elastic EP Scaling 拿到首个完成请求的速度,比重启快 5.3×–8.2×。
路线图与当前状态
| 阶段 | 能力 | 截至 2026 年 10 月 4 日状态 |
|---|---|---|
| 1/N | Runtime eager EP scale-up | 已合并,PR #30164 |
| 2/N | Scale-up 后 EPLB | 已合并,PR #30553 |
| 3/N | Full-decode CUDA graph recapture | 已合并,PR #33723 |
| 4/N | 按 DP-attention shard 粒度扩容 | 已合并,PR #33728 |
| Later | Scale-down 与 grow-back | 评审中,PR #33111 |
| Later | Fully idle progress | 计划中 |
| Later | Recovery after scale-up | 计划中 |
Scale-up 后的 EPLB
扩容提交之后,SGLang 会在扩展后的拓扑上接着做已有的 EPLB reshuffle,新接纳的 ranks 同样能分到 experts。
CUDA graph recapture
EP4 上捕获的 graph 带着与拓扑相关的状态,没法原样拿到 EP6 上重放。早期的扩容路径只支持 eager execution;PR #33723 合并后,SGLang 已经能在 commit 之前为扩展后的拓扑重新捕获 full-decode CUDA graphs。问题是 prefill 和 piecewise recapture 目前还不支持。
用 256 个 GSM8K examples、50 个 request threads 跑了多次,扩容后的平均输出吞吐如下:
| Transition | Eager | Full-decode CUDA graph |
|---|---|---|
| EP4→EP6 | 371 tok/s | 1,241 tok/s |
| EP7→EP8 | 358 tok/s | 1,120 tok/s |
这套设置下,full-decode CUDA graphs 的平均输出吞吐比 eager execution 高出 3.1×–3.3×。
Multi-rank DP-attention shards
已合并的布局最初把一个物理 EP rank 对应到一个逻辑 DP worker。后来的 PR #33728 允许一个 DP-attention replica 横跨 [[保留6]] 个物理 ranks,这里的 CP 指的就是 Context Parallelism。attention TP × attention CP举个例子,TP2、CP1 配置下加入 ranks 4–5,DP2/EP4 就变成 DP3/EP6;再加入 ranks 6–7,则达到 DP4/EP8。API 表达目标规模时,用的仍然是物理 EP units。

图 4:增加一个 TP2/CP1 DP-attention shard,DP2/EP4 即可扩展为 DP3/EP6。
总结
Elastic Expert Parallelism Scaling 让 SGLang 的 MoE 推理部署离云原生服务那种弹性更近了一步:容量能按 ranks 细粒度增长,不必在完整副本和全量重启之间二选一。做法是把 SGLang 的控制面、Mooncake PG 的弹性 membership 和 NIXL 的 expert data plane 拼到一起,在运行时安全地扩大 EP 拓扑。
目前这一能力已覆盖 eager scale-up、扩容后 EPLB、full-decode CUDA graph recapture,以及 DP-attention shard 粒度扩容。scale-down、grow-back、fully idle progress 和扩容后的恢复能力还在后面,等它们补齐,完整弹性推理生命周期才算走完。