WideEP:大规模专家并行(Expert Parallelism)部署实战
什么是 WideEP
WideEP(Wide Expert Parallelism)不是 SGLang 里的一个具体模块,而是社区对一种大规模 MoE 部署模式的俗称。官方文档里叫 Large-Scale EP。
核心思路只有一句话:
把 Expert Parallelism 撑得很宽(几十到上百张 GPU),配合 DP Attention 消除通信,用 DeepEP 解决 All-to-All 瓶颈。
为什么需要 WideEP
以 DeepSeek-V3/V4 为例:256 个 routed expert,FP8 权重约 25GB,加上 dense 层、KV Cache,单机 8 卡跑高吞吐 decode 场景显存压力极大。
传统方案有三个瓶颈:
| 方案 | 瓶颈 |
|---|---|
| TP(Tensor Parallel) | 所有卡存全部专家,每卡 ~25GB,显存放不下 |
| 普通 EP(8 卡) | 每卡 ~32 个专家,batch 小,HBM 带宽利用率低 |
| 无 DeepEP 的 EP | NCCL All-to-All 延迟高,跨机扩展不了 |
WideEP 的解法:用更多卡分摊专家 → 每卡只存 4 个专家 → batch 变大 → HBM 利用率高;DP Attention → 省掉 KV Cache 冗余。
WideEP 的核心组成
1. Expert Parallelism(MoE 层)
1 | 256 experts ÷ 64 张卡 = 每卡 4 个专家 |
token 经过 gate 计算 TopK 后,通过 DeepEP All-to-All 精确 dispatch 到目标专家所在卡,算出结果再 combine 回来。
2. DP Attention(Attention 层)
传统 TP 下 Attention 需要 AllReduce 汇总,跨 64 卡延迟巨大。WideEP 改用 Data Parallel:
- 每卡存一份完整的 Attention 权重(QKV/O projection)
- 每卡独立算自己的 batch,KV Cache 独立不共享
- 零通信,省掉 AllReduce
为什么放得下?DeepSeek-V3/V4 的 dense 层(Attention + Gate + Shared Expert + Norm)总共才 ~4GB,复制 64 份完全没问题。
3. DeepEP All-to-All
DeepEP 是 DeepSeek 开源的 MoE 专用通信库,解决了 NCCL 做 All-to-All 的三大问题:
| 特性 | NCCL All-to-All | DeepEP |
|---|---|---|
| 通信粒度 | 全量 | 按 token routing 结果精确发送 |
| SM Overlap | 不支持 | 支持(通信和 GEMM 重叠) |
| Low Latency 模式 | 无 | 有(decode 专用) |
| 跨节点 | 一视同仁 | NVLink + IB 分层优化 |
各层并行方式一览
| 层 | 并行方式 | 通信 |
|---|---|---|
| Embedding / RMSNorm | 每卡完整副本(DP) | 无 |
| Attention QKV / Output | 每卡完整副本 | 无 |
| Attention compute | DP,每卡独立 batch | 无 |
| KV Cache | 每卡独立 | 无 |
| MoE Gate | 每卡完整副本 | 无 |
| MoE Experts | EP,每卡 4 个 | DeepEP All-to-All |
| Shared Expert / LM Head | 每卡完整副本 | 无 |
关键设计取舍:dense 层(4GB)复制 64 份 → 省掉通信;MoE 层(25GB)必须 EP 切分 → 靠 DeepEP 通信。
关于 --tp 64 的误解
很多人看到 --tp 64 以为权重被切了 64 份,其实不是。
在 SGLang 里,tp 只是定义一个包含 N 张卡的通信组,组内的并行方式由其他参数决定:
1 | # parallel_state.py |
两个都是 1,意味着没有任何层做真正的 Tensor Parallel 切分。tp=64 的真实含义是”这 64 张卡组成一个协作集群”,具体怎么分工由 ep_size、dp_size 等参数决定。
SGLang 配置示例
基础 WideEP(单机 8 卡)
1 | python -m sglang.launch_server \ |
完整 WideEP(DP Attention + 低延迟模式)
1 | python -m sglang.launch_server \ |
多节点部署(2 × 8 卡)
1 | # Node 0 |
两个重要的优化特性
TBO(Two-Batch Overlap)
把请求拆成 micro-batch,在 attention 和 dispatch/combine 之间穿插执行:
1 | --enable-two-batch-overlap |
- 吞吐量最高提升 2×
- 零额外显存开销
- 原理:attention 算完 → yield → dispatch 和下一个 batch 的 attention 并行
EPLB(Expert Parallelism Load Balancer)
运行时收集 expert 激活统计,动态调整 expert 放置/复制策略,解决负载不均:
1 | --enable-eplb |
配合大 batch size(如 --max-running-requests 128)效果更好。
与之前方案的对比
WideEP vs 无 DeepEP 的 EP(moe-a2a-backend=none)
a2a_backend=none |
WideEP(deepep) |
|
|---|---|---|
| token 跨卡 | ❌ 不移动 | ✅ 精确 dispatch |
| 每卡计算 | 只算本地 expert + AllReduce | 只算本地 expert(无 reduce) |
| 可扩展性 | 最多 8~16 卡 | 64~128+ 卡 |
| 通信算子 | AllReduce | DeepEP All-to-All |
| KV Cache | TP 共享(冗余) | DP 独立(不冗余) |
none 模式下,token 不跨卡,每卡算完自己的 expert 后 AllReduce 汇总——浪费计算(路由到的 expert 不在本卡就白算),跨机扩展不了。
通信 Backend 选择
| Backend | 描述 | 约束 |
|---|---|---|
none(默认) |
用 AllReduce/AllGather | 支持 ep < tp(混合 EP+TP) |
deepep |
DeepEP 通信库 | 必须 ep == tp |
mooncake |
弹性推理 + RDMA | 必须 ep == tp |
mori |
AMD ROCm 优化 | 必须 ep == tp,仅支持 normal 模式 |
flashinfer |
FlashInfer All-to-All | 无特殊约束 |
总结
WideEP = DP Attention + EP MoE(DeepEP All-to-All),本质上就是:
- MoE 层:专家分散到 64+ 卡,DeepEP dispatch/combine
- Dense 层:每卡完整副本,DP 独立算,零通信
- **
tp=64**:只是通信组大小,不代表 TP 切分(moe_tp_size=1)
DeepEP 出来之前,大规模 EP 做不了——NCCL All-to-All 延迟太高。DeepEP 解决了这个瓶颈,WideEP 才成为实用的部署模式。
参考文档: