本文目录
MoE 的 router 为每个 token 选择少数 experts。即使长期看每个 expert 获得的 token 数相近,一次在线 batch 仍可能很倾斜;如果某些主题、语言或请求类型反复命中同一组 experts,热点还会持续存在。
在 Expert Parallel 中,这种倾斜会同时影响三件事:热点 rank 接收更多 dispatch 数据、执行更大的 expert GEMM、最后完成 combine。其他 ranks 即使早已完成,也要等待最慢者。因此整层延迟通常更接近:
\[T_{MoE}\approx\max_r \left(T_{dispatch,r}+T_{expert,r}+T_{combine,r}\right)\]而不是所有 rank 平均耗时。
“MoE 负载均衡”常被当作一个概念,实际至少包含两类完全不同的机制:
- 训练时路由均衡:改变 router 的学习信号或选择偏置,让逻辑 experts 获得更均匀的 token;
- 部署时物理均衡:不改变模型选中的逻辑 expert,通过复制热点 expert、调整 placement、在等价副本间分流,使 GPU 负载更均匀。
前者会影响模型学到的专家分工,后者是 serving 系统的执行映射。把二者混在一起,容易让 runtime 为了性能擅自改掉 checkpoint 语义,或者误以为训练均衡后线上就不再需要调度。
先区分逻辑 expert 与物理 expert
模型 checkpoint 定义 $E$ 个逻辑 experts:
logical experts: e0, e1, e2, ..., e(E-1)
Router 输出的是逻辑 expert id。若没有副本,每个逻辑 expert 对应一个物理权重实例:
e0 → GPU0 slot0
e1 → GPU0 slot1
e2 → GPU1 slot0
...
EPLB 可以为热点逻辑 expert 建立多个完全相同的物理副本:
logical e5
├── physical replica e5#0 on GPU1
├── physical replica e5#1 on GPU4
└── physical replica e5#2 on GPU7
Router 仍然选择 e5,runtime 再从 e5#0/#1/#2 中选择一个执行。只要权重、数值路径和 router weight 一致,这些副本在模型语义上等价;改变的是 token 去哪张 GPU,而不是 token 由哪个逻辑 expert 处理。
因此需要两张映射表:
physical_to_logical[physical_slot] → logical_expert
logical_to_physical[logical_expert] → [replica slots...]
DeepSeek 开源 EPLB 的输出正是这两类映射,以及每个逻辑 expert 的副本数量。通信 dispatcher 要消费的是最终 physical destination,但日志和模型语义仍应保留 logical id。
三个层级的“不均衡”
只看每个 expert 的平均 token 数不够。至少要在 expert、rank 和 node 三层测量。
Expert load
设一层本轮共有 $N_a$ 个 assignments,逻辑 expert $e$ 收到 $n_e$:
\[\bar n_e=\frac{N_a}{E}\] \[I_{expert}=\frac{\max_e n_e}{\bar n_e}\]它回答“最热逻辑 expert 是平均值的多少倍”。
Rank load
rank $r$ 上物理 experts 的总负载为:
\[L_r=\sum_{p\in\mathcal P_r}\ell_p\]其中物理副本 $p$ 的负载为 $\ell_p$。Rank imbalance:
\[I_{rank} =\frac{\max_r L_r}{N_a/P_e}\]两个中等热点 experts 若放在同一 GPU,expert 指标可能不夸张,rank 却成为明显 straggler。
Node load 与跨节点 traffic
节点 $m$ 的总负载:
\[L_m=\sum_{r\in m}L_r\]节点间均衡不只影响计算,还影响 RDMA 入流量。如果一个 expert group 的所有副本都在同一节点,选择该组的 token 会集中穿过网络。
三个指标需要逐层统计,因为不同 MoE layers 的专家分工不同。把所有层合成一个平均值,会掩盖少数关键层的热点。
训练时辅助损失在做什么
经典 Top-$k$ routing 只优化主任务,router 可能把大量 token 集中到少数 experts。训练系统常增加 auxiliary load-balancing loss,让“路由概率”和“实际选择频率”更均匀。
一种抽象写法是:对 expert $e$,设 $f_e$ 为被选择的 token 比例,$q_e$ 为平均 routing probability,则:
\[L_{balance} =\alpha E\sum_{e=1}^{E}f_eq_e\]具体公式因 Switch Transformer、GShard、模型实现而不同,但目的相似:给热点路由增加代价。
问题在于 auxiliary loss 的梯度会与语言建模主目标共同更新 router。系数太小,均衡效果不够;系数太大,模型可能为了均匀而牺牲最合适的专家选择,形成所谓 interference gradient。
这属于训练时模型设计。Serving runtime 只能执行 checkpoint 已经学到的 router,不能在推理阶段临时增加 loss 修复热点。
Auxiliary-loss-free balancing 的思路
DeepSeek-V3 使用了一种不把全局均衡项直接加入主训练损失的策略。核心是在 Top-$k$ 选择前,为每个 expert 的 affinity score 加一个动态 bias:
\[s'_e(x)=s_e(x)+b_e\]Top-$k$ 使用 $s’_e$ 决定选谁;用于合并 expert output 的 gating weight 仍基于原始 affinity score 的模型定义。训练过程中根据近期 expert load 更新 $b_e$:
- expert 过载,降低其 bias;
- expert 欠载,提高其 bias。
可以把一个简化更新写成:
\[b_e^{(t+1)} =b_e^{(t)}+\eta\,\operatorname{sign}(\bar n-n_e)\]实际实现的统计窗口、更新规则和 group 限制应以模型论文/代码为准。关键区别是:均衡信号通过选择偏置调节,而不是让辅助损失梯度直接干扰主任务表示学习。
“loss-free”不等于完全没有其他辅助约束。DeepSeek-V3 技术报告还保留了较小的 sequence-wise balance loss,用来避免单个 sequence 内的极端不均衡。名称描述的是核心全局策略,而不是所有均衡项都消失。
训练完成后,bias 已是 checkpoint/router 语义的一部分。推理不能为了当前 GPU 负载随意修改它,否则逻辑 expert 选择会改变,输出质量也可能变化。
为什么训练均衡仍解决不了线上倾斜
训练数据分布与线上请求不完全相同。即使训练全局统计均匀,serving 仍会出现:
- 某个租户集中发送一种语言或领域;
- 白天和夜间的 request mix 不同;
- Prefill 大 batch 与 Decode 小 batch 方差不同;
- continuous batching 把相关请求聚到同一轮;
- 单个长 prompt 在一层产生大量相似 routing;
- 小 batch 的随机波动让某 rank 瞬时过热;
- expert placement 把多个次热点放在同一 GPU。
训练均衡优化的是模型分工的长期统计,EPLB 优化的是特定部署和当前 workload 下的物理执行。两者互补,不是替代关系。
EPLB 的输入不是 Router logits,而是负载估计
DeepSeek EPLB 的核心函数接收形如:
weight[layer, logical_expert]
的负载矩阵。weight[l,e] 表示第 $l$ 层逻辑 expert $e$ 的预计工作量。仓库明确说明“如何预测 expert load”不在其范围内,常见输入是历史统计的 moving average。
一个基础 EMA 为:
\[\hat n_e^{(t)} =\beta\hat n_e^{(t-1)}+(1-\beta)n_e^{(t)}\]$\beta$ 大,placement 稳定但追踪热点慢;$\beta$ 小,响应快却容易随 batch 噪声反复迁移。
负载不一定只用 token count。若不同 experts 的 GEMM kernel、量化格式或命中行为不同,可以估算实际 service time:
\[w_e =a\cdot n_e+b\cdot \text{bytes}_e+c\cdot T_{gemm,e}\]但官方 EPLB 简化算法以给定 weight 为基础,并不自动学习这个成本模型。接入系统需要先证明 token count 与 layer/rank time 的相关性。
怎样给热点 expert 分配副本
设逻辑 experts 数为 $E$,可用物理 slots 数为 $E+R$,其中 $R$ 是 redundant experts 数。每个逻辑 expert 至少有一个副本,额外 $R$ 个 slots 分给热点。
若 expert $e$ 有 $c_e$ 个副本,并能理想均匀分流,它的单副本负载近似:
\[\ell_e=\frac{w_e}{c_e}\]目标是选择整数 $c_e\ge1$,满足:
\[\sum_e c_e=E+R\]并尽量降低最大单副本负载:
\[\min \max_e\frac{w_e}{c_e}\]EPLB 使用一个直观的贪心过程:每次把新副本分给当前 weight / replica_count 最大的逻辑 expert。伪代码为:
replica_count[e] = 1 for every logical expert
repeat R times:
e = argmax(weight[e] / replica_count[e])
replica_count[e] += 1
一个例子
4 个逻辑 experts 的历史负载为:
e0=100, e1=55, e2=25, e3=20
有两个冗余 slots:
- 第一个副本给 e0,估算单副本负载从 100 降到 50;
- 此时 e1=55 最大,第二个副本给 e1,降到 27.5。
最终:
e0 replicas=2 → ~50 each
e1 replicas=2 → ~27.5 each
e2 replicas=1 → 25
e3 replicas=1 → 20
若第二个副本继续给 e0,其单副本约 33.3,但 e1 仍为 55,最大负载更差。这个例子说明“只复制最热 expert”不一定使全局最大值最小。
有副本后,Token 去哪个物理 slot
复制权重只是第一步。Router 仍输出 logical expert,runtime 必须在其合法副本中选一个 physical destination。
最简单的静态均匀分流可以使用 round-robin 或 hash:
replicas = logical_to_physical[e]
p = replicas[hash(request_id, token_position, layer_id) % len(replicas)]
这种方法无需跨 rank 实时交换队列长度,但只能实现统计均匀。动态选择可以考虑:
- 当前 batch 已分给每个副本的 assignment 数;
- GPU queue、expected GEMM time;
- source 与 replica 是否同节点;
- 通信 buffer 和 NIC 拥塞;
- 副本是否 ready。
选择过程本身不能比要节省的 latency 更贵。Decode 小 batch 若为了每个 token 运行一次全局调度或同步所有 rank load,可能得不偿失。
还要保持确定性映射的边界:同一 assignment 只能发给一个副本;combine 仍把结果映射回原 logical expert/Top-$k$ slot。副本不是让一个 token 重复算多次再投票。
把物理 experts 装箱到 GPUs
得到副本集合后,还要把 physical experts 放入固定容量的 GPU slots。设每张 GPU 必须保存 $S$ 个 experts,EPLB 的 balanced_packing 按负载从大到小处理,并把每个 expert 放入当前总负载最小、且仍有 slot 的 GPU。
可以理解为带等数量约束的 greedy bin packing:
sort physical experts by estimated load descending
for expert in sorted list:
choose GPU with:
- available expert slot
- minimum current total load
place expert
add its estimated load to GPU total
严格最优的装箱是组合优化问题,贪心不保证全局最优,但计算快、结果可解释,适合周期性重平衡。评估时应比较重排前后的预测最大 rank load,并用真实 trace replay 验证,而不是因为算法名含 “balancer” 就默认一定改善。
Hierarchical policy:先平衡节点,再平衡 GPU
DeepSeek-V3 使用 group-limited routing:experts 被划为 groups,一个 token 只从有限 groups 中选择 experts。这给 topology-aware placement 一个机会。
当 expert group 数能被节点数整除时,EPLB 的 hierarchical policy 按三步处理:
- 按 group 总负载,把 expert groups 均衡装到 nodes;
- 在每个 node 内,为热点 experts 建立冗余副本;
- 把 node 内的物理 experts 均衡装到各 GPUs。
logical expert groups
│ balance group load
▼
nodes
│ replicate hot experts inside node
▼
physical expert replicas
│ balance replica load
▼
GPUs inside each node
好处是同组 experts 尽量留在同一节点,配合 group-limited routing 减少跨节点 fan-out。代价是副本只能在较小的节点域内分配,某节点特别热时不能充分借用其他节点的空闲 GPU。
官方 EPLB 说明该策略可用于 EP size 较小的 Prefill 阶段。
Global policy:忽略 group 边界,全局平衡副本
当 group/node 条件不适用时,EPLB 使用 global policy:把所有 experts 视为一个全局集合,跨全部 GPUs 复制与装箱。
它有更大的均衡自由度,适合 EP size 较大的 Decode 部署,但可能增加跨节点 traffic。是否更快取决于:
\[\text{straggler reduction} \quad\text{vs}\quad \text{additional network cost}\]不能只比较 rank token count。一个 plan 把最大 rank load 降低 20%,若同时让大量 assignment 从 NVLink 变成 RDMA,端到端 TPOT 可能恶化。
因此候选 placement 的评分应包含拓扑成本,例如:
\[J =\lambda_1\max_r L_r +\lambda_2 V_{inter-node} +\lambda_3 M_{migration}\]其中 $M_{migration}$ 是从当前 plan 切换所需移动/加载的 expert 权重。权重系数来自实际硬件 profile,而不是固定经验值。
Prefill 与 Decode 为什么可能用不同 Plan
DeepSeek 官方 EPLB 把 hierarchical policy 与 Prefill、小 EP,把 global policy 与 Decode、大 EP 联系起来。原因可以从 workload 推导。
Prefill
- 每轮 token 多,专家负载统计相对稳定;
- expert GEMM 较大;
- 大 payload 的跨节点带宽成本明显;
- 较小 EP domain 可以在节点组内形成高吞吐。
Hierarchical placement 能限制跨节点流量,同时在节点内平衡大 batch。
Decode
- 每轮 token 少,瞬时方差大;
- expert GEMM 小,straggler 对 TPOT 敏感;
- 模型总权重可能需要更大的 EP domain;
- 更全局的副本池提供更高分流自由度。
P/D 解耦时,两边可以使用不同 physical mapping;但权重管理、路由 metadata、KV 交接与监控必须明确当前 pool 的 plan version,不能把 Prefill 的 physical id 直接当成 Decode 的 physical id。跨阶段传递 logical expert 语义即可,KV 本身也不应依赖某个 expert physical slot。
No Token Dropping 与负载均衡的关系
一些 MoE 训练实现为每个 expert 设置容量,超出 capacity 的 assignments 被丢弃或重新路由。推理时 dropping 会改变模型计算,可能影响输出质量。
EPLB 通过副本和 placement 分摊热点,但不能保证任何突发 batch 都不会超过 buffer/compute 上界。若目标是 dropless inference,还需要:
- 动态或足够大的 dispatch buffer;
- 对极端热点进行 chunked expert execution;
- 不把 padding capacity 当作真实丢弃策略;
- 在 admission control 层限制无法承载的总 token;
- overflow 时明确 fallback/recompute,而不是静默删除 assignment。
“有 EPLB”不自动等于“永不丢 token”。正确性承诺来自整条 runtime 数据路径。
负载统计窗口怎样选
EPLB 仓库不负责预测 load,实际系统需要决定采样、聚合与更新时间。
过短窗口
直接用最近一个 batch:
- 对热点响应快;
- 容易追逐随机噪声;
- plan 频繁变化;
- 权重迁移与缓存失效可能大于收益。
过长窗口
使用数小时平均:
- placement 稳定;
- 无法追踪租户/时段变化;
- 切流后旧统计污染新 workload;
- 热点已造成 SLO 下降,plan 仍迟迟不变。
可以使用多时间尺度:
fast EMA → detect sudden skew / alert
slow EMA → generate stable placement candidate
trace replay → validate candidate before rollout
再加入 hysteresis:只有候选 plan 的预测收益超过阈值并持续若干窗口,才触发重排。切换后设置 cooldown,避免在两个近似 plan 间振荡。
负载还应按 Prefill/Decode、模型 revision、Adapter、租户或 request class 分层。混在一起的平均值可能不代表任何实际 worker pool。
重排不是更新一张表这么简单
新的 physical_to_logical plan 意味着某些 GPU slot 要换成另一份 expert 权重。安全 rollout 可以分为:
1. generate candidate plan from stable load statistics
2. replay trace / estimate rank and network cost
3. load new or changed expert replicas into spare/staging memory
4. verify checksum, dtype and model revision
5. publish plan generation N+1 at a batch/layer-safe boundary
6. route new assignments using N+1
7. wait for plan N in-flight operations to finish
8. release old replicas and buffers
若显存没有 staging 空间,可以 drain 整个 worker group 后重载,但切换成本更高。不能在某些 ranks 已使用新 mapping、另一些仍使用旧 mapping 时开始 All-to-All;同一个 logical id 会被解释为不同 physical destination。
所有 dispatch handle、日志与 profile 应携带:
model_revision
layer_id
placement_generation
physical_to_logical checksum
失败回滚也以完整 EP group 为单位。旧 plan 至少保留到所有使用它的 in-flight MoE operations 完成。
副本的显存成本
冗余 expert 是用显存换负载均衡。一个 gated FFN expert 常包含 gate/up/down matrices。粗略权重大小为:
\[M_{expert} \approx (2H I + I H)\times b_w =3HIb_w\]其中 $H$ 是 hidden size,$I$ 是 expert intermediate size,$b_w$ 是每权重字节数;量化 scale、alignment 和 runtime layout 还会增加开销。
$R$ 个冗余副本约增加:
\[M_{redundant}\approx R\times M_{expert}\]这些显存原本可能用于 KV Cache、larger batch 或通信 buffer。vLLM 的 Expert Parallel 部署文档也提醒,开启 redundant experts 会有明确的额外显存成本;具体数值与模型和精度绑定,不能跨模型照搬。
因此要用 goodput 评估:副本减少的 straggler 是否足以抵消 KV 容量下降或可并发请求数减少。
实时动态均衡的边界
静态/周期 EPLB 处理的是相对稳定的专家热点。小 Decode batch 还有很强的瞬时波动:即使历史完全均衡,本轮也可能随机把很多 token 分到同一 rank。
更动态的方法可以在有多个合法副本时,根据本轮 load 实时选择;DeepSeek 的 LPLB 仓库还探索使用线性规划在既定副本拓扑上重分配 token flow。但官方明确将其标为早期研究阶段,并列出:
- solver 延迟对小 batch 可能不可忽略;
- 当前目标主要按 token count,不完全代表 grouped GEMM 非线性耗时;
- 极端全局倾斜下不一定优于 EPLB;
- 需要额外的实时负载同步与通信。
所以动态优化不应替换掉稳定基线。更合理的层级是:
training router balance
→ periodic expert replication/placement (EPLB)
→ cheap per-batch replica selection
→ experimental optimizer for residual skew
每层只解决前一层剩余的问题,并接受严格的调度开销预算。
正确性验证
EPLB 改变执行位置,不应改变逻辑输出。验证需要覆盖:
权重一致性
同一 logical expert 的所有 replicas 必须来自相同 model revision、dtype 和量化参数,checksum 一致。Adapter 或 expert-specific delta 也必须一同复制。
映射互逆
对每个 physical slot:
logical = physical_to_logical[p]
assert p in logical_to_physical[logical]
每个 logical expert 至少有一个 ready replica。
Assignment 守恒
切换 plan 前后,logical Top-$k$ ids 与 router weights 完全相同;每个 assignment 恰好选择一个 physical replica。
数值对照
固定输入分别在无副本 baseline、旧 plan、新 plan 上执行,逐层比较 MoE output。若 kernel 的浮点归约顺序不同,应使用有依据的误差阈值,并另行评估最终生成差异。
极端与故障场景
- 所有 token 选择同一个逻辑 expert;
- 某 replica 在切换期间不 ready;
- plan event 延迟到达;
- 一个 rank 加载失败;
- plan generation 回滚;
- buffer capacity 小于瞬时热点;
- worker group 在 in-flight combine 时重启。
任何 rank 无法采用新 plan 时,整组都不能发布该 generation。
应该监控哪些指标
Router 层
logical assignments per expert/layer
expert max-to-mean and entropy
Top-k group distribution
Prefill vs Decode routing histogram
Physical placement 层
physical assignments per replica
rank/node max-to-mean
replica split ratio
local vs cross-node assignments
predicted vs observed rank time
Rebalance 生命周期
plan generation and checksum
candidate predicted gain
expert bytes moved
load/warmup duration
rollout success/failure
time since last rebalance
Serving 结果
dispatch / expert GEMM / combine P50-P99
TPOT and TTFT SLO attainment
KV capacity lost to replicas
goodput before/after
特别值得看“预测最大 rank load”与“实际最慢 rank time”的偏差。如果长期不相关,说明 token count 不是足够好的成本模型,或瓶颈其实在网络、kernel shape、NUMA/NIC 拓扑。
评估一个 EPLB Plan
可以使用最近一段真实 routing trace 做离线 replay:
- 按 layer 统计 logical expert load;
- 用训练窗口生成 candidate replica/placement;
- 在独立验证窗口上把 assignments 映射到 physical replicas;
- 计算每轮 rank/node load 与跨节点 bytes;
- 用 profile 得到的 GEMM/communication cost 估算 layer time;
- 与当前 plan 比较 P50、P95、P99,而非只看平均;
- 扣除副本显存、权重加载和切换成本;
- 通过后再小流量 rollout,观察真实 SLO。
避免用同一段 trace 同时拟合和验证,否则 candidate 会过度适配历史热点。还要在 request mix 改变、流量突发和均匀路由三种场景下验证,确保 plan 不只在单一窗口有效。
一个可执行的接受条件可以是:
P99 rank-load imbalance decreases by target
P99 MoE layer time does not regress
cross-node bytes remain within budget
KV capacity reduction is acceptable
no output correctness regression
rebalance completes within operational window
实施顺序
第一阶段:测清楚倾斜
- 记录逐层 logical expert counts;
- 聚合到 rank/node 并关联 layer time;
- 分开 Prefill、Decode 与主要 workload;
- 验证热点是持续的还是 batch 噪声。
第二阶段:只重排,不增加副本
- 保持每个 logical expert 一个 physical instance;
- 把多个热点拆到不同 GPUs;
- 验证 mapping generation 与安全 rollout;
- 量化节点间 traffic 变化。
第三阶段:加入少量冗余 experts
- 从最热 logical experts 开始;
- 用真实显存 layout 计算副本成本;
- 建立副本选择和 assignment 守恒检查;
- 比较 goodput,而不是只看均衡比。
第四阶段:周期与拓扑优化
- EMA、hysteresis 与 cooldown;
- hierarchical/global plan 对比;
- Prefill/Decode 独立 plan;
- trace replay 和自动 rollback。
第五阶段:评估动态算法
- 先衡量剩余 per-batch skew;
- 给 planner 设置严格微秒级预算;
- 计入实时同步开销;
- 保留静态 EPLB fallback。
小结
MoE 负载均衡不是一个开关,而是从模型训练到物理部署的多层控制系统。
可以用五条边界把它理清:
- 训练 auxiliary loss 或 dynamic bias 决定逻辑 experts 怎样被选中;
- EPLB 不改变 Top-$k$ 逻辑选择,只复制热点 experts 并调整物理 placement;
- Expert 均衡不等于 rank/node 均衡,必须把多个 experts 的负载与网络拓扑合并观察;
- 副本用权重显存换 straggler 改善,最终应以 TTFT/TPOT goodput 衡量;
- Rebalance 是带 generation 的分布式 rollout,不是原地改一张索引表。
当 logical/physical 两层被清楚分开,训练策略、EPLB、DeepEP 就能各司其职:模型决定哪些 experts 合适,EPLB 决定等价副本放在哪里,DeepEP 负责 token 怎样高效到达那里。再向更大集群扩展时,问题就变成 Wide EP:当一个 EP group 横跨数十乃至数百 GPU,怎样控制 fan-out、层次化通信、并行分组和全局负载波动。
参考资料
觉得有帮助?
分享给同样关注系统性能的人。