MoE 专家并行的 all-to-all:两跳通信与吞吐波动

在 **** 的国产卡集群上(8 卡,单卡 64GB HBM,机内卡间互联 392 GB/s,跨机走 RDMA 以太网,机内无全互连交换)以 BF16 加载 DeepSeek 类 671B 稀疏 MoE(MoE 加 MLA 注意力),专家分散到多卡、跨机排布。decode 阶段吞吐随 EP 规模增大不升反降,或停在一条与单参数调优无关的吞吐上限;把集合通信缓冲区、page-size 这类单参数逐一扫描,改善为 0%。同一套权重换成更低并发的负载,吞吐反而回正,波动比稠密模型剧烈得多。问题落在每层前向的两跳 all-to-all:token 分发到专家所在卡、专家输出再收回来,这两跳的通信量随并发、路由到的专家数与 hidden 维度增长,跨机时还有一条无法隐藏的固定延迟。

专家并行把专家分布到设备

稠密模型每层只有一个 MLP,MoE 每层有多个专家,路由网络给每个 token 选 top-k 个专家。专家并行(EP)把这些专家按设备分摊:每张卡或每个 rank 持有一部分专家,token 按路由结果送到持有对应专家的 rank 上计算。EP 与张量并行、数据并行可以组合,常见做法是 attention 部分走张量并行或数据并行、专家部分走 EP。

一个关键量是「激活参数量」。MoE 每 token 只激活 top-k 个专家,激活参数量远小于总参数量,看起来该省算力。代价在通信:路由把 token 打散到不同设备,每层前向必须先分发、再回收,这部分通信不因「稀疏激活」而消失。

一次前向的两跳 all-to-all

每层 MoE 的前向里,通信分两跳:

  1. 分发(dispatch):路由网络给出每个 token 命中的 top-k 专家后,把 token 按目标专家所在 rank 分组,通过一次 all-to-all 送到各 rank。每个 rank 收到本卡专家要处理的 token,且这些 token 可能来自任意源 rank。
  2. 回收(combine):各 rank 的专家算完后,把输出按原 token 顺序送回它来的 rank,再按路由权重加权求和。这是第二跳 all-to-all。

两跳是配套的:分发打乱了 token 与 rank 的对应关系,回收必须按同样规则还原。一个千亿级 MoE 有几十层,每层都付这两跳,层数是乘数。

每 rank 每跳通信量 ≈ 本 rank 发出的 token 数 × top_k × hidden × 每元素字节数
一次前向 两跳 = dispatch + combine,各一次 all-to-all

通信量随什么增长

增长项 影响 说明
token 数(并发 × 序列长) 线性放大 每个 token 都要分发与回收,批量越大每层通信量越大
top_k 线性放大 路由到 k 个专家,分发量约为单专家的 k 倍
hidden 维度 线性放大 每 token 传的是 hidden 维向量
精度 / 每元素字节数 线性放大 BF16 每元素 2 字节,FP8 降到 1 字节
专家分散度(跨机跳数) 抬高固定延迟与链路层级 专家摊到越多机器,all-to-all 越容易跨机,固定延迟项上升

前三项是通信量的乘数,末一项是延迟项。跨机与机内的差别不在带宽一处:机内全互连一跳可达,跨机要做节点间路由,引入一个与数据量无关的固定延迟,这部分无法靠重叠计算隐藏。

现象

同一处通信约束会以几种形态出现:

仓库中一条记录给出的量化结果(非本机实测):EP 通信约 61% 可被计算隐藏,其余约 39% 暴露在 decode 关键路径上,跨机固定延迟项约 58 ms/层,帧时间近似为 T_fwd = β · batch + 固定延迟,batch 增大时被固定延迟项钳住。这条记录对应的是「无全互连、跨机多跳」的部署形态。

定位步骤

  1. 拆算子计时:把 moe.dispatch、moe.combine、moe.expert_compute(grouped GEMM;算子名取自 SGLang profiler,非 vLLM 命名)与 all-reduce 分开抓耗时,看热点落在 dispatch、combine 还是专家计算。三者不拆开时,「MoE 慢」无法定位到哪一跳。
  2. 算通信占比与可隐藏比例:统计 trace 里 all-to-all 等待段里有多少落在计算重叠窗口之外。暴露比例高说明通信落在关键路径上。
  3. 看利用率形态:所有 rank 同步低位且 all-to-all 等待固定出现,是通信瓶颈;个别 rank 低位、其余高位,是专家负载不均;rank 都高位却慢,是专家计算本身的算力问题。
  4. 变并发扫一遍:固定模型与 EP 度,把 --max-running-requests 从低到高扫,记录 decode 吞吐与 dispatch 耗时。吞吐随并发非单调、且拐点位置随部署形态移动,是通信在关键路径上的特征。
  5. 确认命中融合算子路径:核对 resolved_backend(本笔记自设的记录字段,真实凭证是启动日志里那一行),确认 moe.dispatch 命中融合 MoE 实现,还是回退到逐专家的通用实现。融合路径未命中时,路由、top-k、专家 GEMM 未合并,通信与计算都不在预期实现上。
  6. 确认是否跨机:记录 all-to-all 是否跨节点,以及跨机跳数。同拓扑内该算子可用、跨机时出现固定延迟,是区分两类问题的分界。
# 示意:DeepSeek 类模型多机部署的并行配置(参数名取自 SGLang,取值按本机规格填)
python -m sglang.launch_server --model-path <model> \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8

处置:开关与代价

动作 作用 代价 / 前提
调 EP 度 专家摊到更多 rank,可减少单卡专家数 EP 度过大时专家跨机分散,跨机跳数上升,固定延迟项增大,收益反转
专家分组 / 复制策略 减少每层跨机跳数,把专家就近放 需重排专家到设备,占用更多显存
拓扑重构(如双副本布局) 把跨机 all-to-all 压回机内,越过通信固定延迟构成的上限 需成倍的机器与更复杂的部署
换 a2a 后端 用融合的分发/回收实现替代通用集合通信 须确认后端在该栈上可用
调整 dense 与 EP 的配比 把 dense MLP 与专家部分的切分重新分配 需与 TP 度联调,参数名随框架不同
精度转 FP8 每 token 通信量减半 引入量化误差,须核精度
开 MoE 融合算子 路由、top-k、专家 GEMM 合并,减少下发与拷贝 收益不总成立,须按负载验证

调整顺序:先拆开算子计时,判断瓶颈在 dispatch、combine 还是专家计算;确认是通信撞关键路径后,优先减跨机跳数与调 EP 度这类架构层动作,而不是扫单参数。仓库里那条记录的直接结论是:跨机所有算子参数扫描 0% 改善,减少跨机跳数是本轮唯一有效动作,把 EP 单副本跨机换成机内双副本布局后,decode goodput 从 42% 抬到 74%。单参数调优对通信固定延迟上界无效,这一点在 MoE 上比在稠密模型上更常被验证到。

记录字段

# 示意:一条 MoE 专家并行结论的记录(字段名示意)
model:
  model_name:
  expert_count:        # 专家总数
  top_k:               # 每 token 路由到的专家数
  activated_params:    # 激活参数量
  precision:           # BF16 / FP8 / W8A8
hardware:
  card_count:
  node_count:
  interconnect:        # 机内互联带宽 / 跨机链路类型 / 有无全互连
parallelism:
  ep_size:
  tp_size:
  cross_node_hops:     # 每层 all-to-all 的跨机跳数
  moe_dense_tp_size:   # dense 部分与 EP 的配比
  a2a_backend:         # 如 deepep
path:
  moe_dispatch:        # moe.dispatch 命中的实现
  moe_path_enabled:    # 融合 MoE 是否开启
  resolved_backend:
workload:
  request_pattern:     # 短请求 / 长请求 / 混合
  max_num_seqs:
perf:
  decode_throughput:
  itl:
  goodput:
comm:
  dispatch_time:       # 分发耗时占比
  combine_time:        # 回收耗时占比
  exposed_ratio:       # all-to-all 暴露在关键路径外的比例
status:                # 通信瓶颈 / 专家计算瓶颈 / 负载不均;注明结论在哪种负载下成立

小结

MoE 的专家并行把专家摊到不同设备,每层前向付两跳 all-to-all:分发 token 到专家所在 rank、回收专家的输出。通信量随 token 数、top_k 与 hidden 维度线性增长,跨机时多出一条无法隐藏的固定延迟。遇到「同为激活参数量级、吞吐却低于预期且随并发剧变」时,先把 dispatch、combine 与 expert 计算拆开计时,判断瓶颈落在哪一跳;确认是通信撞关键路径后,优先减少跨机跳数与重排专家分组,单参数调优对通信固定延迟上界无效。