大模型推理卡越加越多吞吐上不去,BalanceRoute给出在线路由解法
机器之心编辑部大模型走向大规模在线服务,一个常见却又有些反直觉的现象是:卡加得越来越多,吞吐却涨得越来越慢。问题出在哪?在 DeepSeek 等 MoE 模型的一类部署中,多组计算卡并行处理大量请求,每组既处理各自的请求,又要通过跨组通信,共同完成每一步解码。这意味着解码是齐步走:只要最忙的一组没算完,其他组算得...
问题出在哪?
DeepSeek 等 MoE 模型的一类部署里,多组计算卡并行处理大量请求。每组既要处理自己的请求,又得靠跨组通信共同完成每一步解码。解码因此成了齐步走,最忙的一组没算完,别组算得再快也得等着。
更麻烦的是,请求就算分得一样多,各组实际扛的负载也可能不一样。较轻的一组先算完、干等最忙的一组,成了常态。这种等待随 token 生成反复出现,每一步都等一点,累积下来,部署规模扩大带来的收益就被悄悄吃掉了。
可见瓶颈不在算力,在「谁来等谁」。
香港科技大学周子杰团队与华为 2012 实验室理论部联合提出 BalanceRoute,针对的正是这一瓶颈。团队的路子很直接:先把问题讲清楚,再谈优化——用数学建模刻画同步等待,再把短期负载预测变成在线路由决策。
效果也经得起检验。论文的 96 卡主实验中,采用实际预测器的 BR-H 相对所比较的最强基线,解码吞吐提升约 15%。
这项工作已被 NeurIPS 2026 接收,并已部署于双方共建的 MaaS 推理服务系统 MathBot-Pie。
论文标题:Tackling the Data-Parallel Load Balancing Bottleneck in LLM Serving: Practical Online Routing at Scale
论文标题:Tackling the Data-Parallel Load Balancing Bottleneck in LLM Serving: Practical Online Routing at Scale
论文链接:https://arxiv.org/pdf/2605.06113
代码链接:https://github.com/b010001y/BalanceRoute
请求数量一样,各组之间照样会分出轻重。
负载不均的根源,在于每条请求要搬的 KV 信息并不相同。
大模型出回答分两步走:先做预填充(prefill),把整段输入过一遍,将后续复用到的中间结果存成 KV 缓存;再做解码(decode),一个接一个吐出输出 token。每走一步,都得读取此前输入以及已生成内容对应的 KV 信息。
这套 PD 分离系统里,两个阶段跑在不同的算力上。预填充一结束,路由器就为这条请求挑一个解码工作单元,已攒下的 KV 缓存也跟着搬过去。一个单元可以由多张计算卡拼成。
轮询之类的法子能把新请求挨个分给各组,可它不管每条请求带多少 KV。都是处理两条请求,长上下文那份缓存更多,单步要读、要算的活也更沉。同步约束一卡,请求数持平,轻的组等重的组,仍是常事。
图 1|在预填充结束之后,请求会被派给解码工作单元。图的下半部分画出本次部署中解码步里的计算与同步过程:每一组都包含两个请求,但各组的 KV 总量并不相同,负担较轻的那一组得等最忙的那一组。斜线表示等待。
负载还会随着生成一路变。每多出一个 token,请求就多一份 KV,下一步要对付的上下文又长一截;请求一完成,就退出后面的解码计算。另一头,预填充侧还在不断送新请求进来。某组可能连着好几步都很忙,也可能因为一条请求收尾而忽然松下来。
图 2|解码过程中负载会发生变化:新请求携带预填充阶段得到的 KV 缓存进来,已经在跑的请求随着生成而变重,跑完的请求则离开。负担较轻的单元要等当下最忙的那一组;而同一个请求自始至终都留在原来的单元里。
要把跑着的请求交给另一组,得把已经攒下的 KV 缓存搬过去。算上这笔开销,论文定了分配后不迁移:路由器得在输出长度未知、负载还在变的情况下做选择,请求一旦落下就留在该单元,直到结束。
数学建模,
把同步等待变成决策目标
分析从每一步的同步关系切入,借助数学建模,把各单元相对最重单元的负载差逐项累加,从而得到不均衡指标。假设在第 k 步,单元 g 的负载是 L_g (k),最重单元的负载是 M (k),单元总数为 G。那么单步不均衡可表示为:
I (k) 越大,代表各单元算力分得越不平均;它衡量的是同步等待带来的空转,而长期要做的,是把这种空转在连续解码步骤里的累积压下来。
图 3 给出的例子是四组负载 10、7、6、5,这时 I (k) 等于 12。若给 C 加 4 单位负载,正好与最重单元持平,I (k) 降到 8;加到 5,C 自己成了最重单元,其余三组各多等一份,I (k) 变成 11。
图 3|在填补空闲与抬高尖峰之间做取舍。图中两种接入方式起点相同;蓝色部分代表原有负载,绿色部分代表新增加的负载,斜线区域是空闲差额,粉色则标出峰值被抬高后多出来的等待。所有数值都是示意性的负载单位。
这组数字点出了分配时的核心取舍:新请求接进来,能补上较轻单元的空闲,可一旦把它推成新的最重单元,别的单元就得多等。问题在于,这种比较不能只看当下,要往未来若干步延伸。
预测多远,
说到底,这取决于路由真正需要掌握哪些信息。
一次分配的影响不会停在原地,会顺延到后面的解码过程。两组眼下忙闲相同,其中一组若有请求快结束了,负载可能很快就会放出来。BalanceRoute 的 BR-H 为此设了 H 步窗口,用来估计各组近期的负载走向。
窗口也不是越长越管用。H 太短,快结束的请求可能看不见;H 太长,就算现有请求的长度预测得准,还没到达的新请求和后续分配也会改动负载,更远处的状态就不好定。
预测的目标因此更明确了:对正在运行的请求,先估它在窗口内结束的概率,再估“若在窗口内结束,还要多少步”,两者合起来给出它在窗口内预计还会跑多久。请求若一直超出窗口,就不必细究它在更远处还能生成多少内容。
图 4|看预测窗口里哪些请求已经结束,据此得到短期负载估计,再用它完成评分、分配和更新。上方色条显示各请求持续处于活跃状态的时间跨度;H=80 是示例窗口,A、B 为两个示意请求。
这些预测最后要落成具体分配。BR-H 先估各单元未来 H 步的负载,再比较接入候选请求后每一步能补多少空闲、又会多出多少等待,把收益和代价合成评分,并对较远的步骤降权。为压住决策开销,路由器会结合可用槽位与预计余量挑单元,再按评分选请求或请求组合,一步一步把分配做完。
每接入一次就更新预计负载,下一轮再按最新运行状态重新判断。预测、评分与分配就这样循环往复,持续刷新。
模型要落到真实系统里,毫秒级的路由环节怎么跟上,成了绕不开的一步。
要拿到模型带来的收益,路由决策就得跟得上解码的节奏。团队在 vLLM-Ascend 上搭了一套有状态代理,把各工作单元的负载、空闲槽位和生成进度统一管起来:预填充完成的请求先进等待池,BR-H 再结合全局状态比较候选请求怎么分配;解码端的流式反馈则不停刷新生成进度。图 5|系统结构简化示意。灰色实线表示调度,蓝色粗箭头表示 KV 传输,红色虚线表示状态回传。
接入走的是现有接口,推理引擎核心不用改。系统复用已有的预测与增量更新负载做法,把组合选择压在小规模候选集合内,每轮调度开销因此可控。主实验跑在 96 张昇腾 910C NPU 上,模型为 DeepSeek-V3 671B(W8A8),含 8 个解码工作单元。单轮调度耗时中位数 1.20 毫秒,99% 分位 2.77 毫秒,低于单步解码约 60 毫秒的时间预算。
在高负载、接近饱和的条件下,团队回放了企业生产请求记录和公开的 Azure-2024 请求记录,与轮询、最短队列等 4 种常用路由策略做对比。用实际预测器的 BR-H,解码吞吐相对各数据集上吞吐最高的基线分别提升 15.4% 和 14.5%,输出 token 间隔的尾部延迟同步下降。模型与 NPU 配置都没变,收益来自请求分配的改进。图 6|实际预测器下的解码吞吐。图中展示已有 vllm-router 基线与 BR-H 的对比。
系统应用方面,BalanceRoute 已经部署在双方共建的 MaaS 推理服务系统 MathBot-Pie 中。MathBot-Pie 以 cache 感知调度为基础框架,靠 Agent 快速自动适配,并自动构建与优化高性能算子和模型,把推理框架、模型计算与底层算子放在一起联合优化,目标指向低时延与高性价比。BalanceRoute 在其中承担的角色,是减少跨组同步等待、拉高在线解码吞吐。
把运筹学写进推理系统
请求不断到达,KV 缓存随生成增长,请求结束又释放负载,跨组同步把这些变化彼此牵住,一次分配对整体效率的影响很难直接判断。团队用建模把这些关系理清,提炼出反映同步等待的负载不均衡指标 I (k),路由问题由此变成一个目标明确的优化问题。顺着这个目标,团队继续分析负载随时间的变化,把预测重点放在近期哪些请求会结束上,形成短期预测与路由策略,并在真实系统里验证了收益。
香港科技大学周子杰团队做 OR for LLM serving(面向大模型服务的运筹学研究),出发点也在这里:先通过建模理解复杂系统,弄清该优化什么、需要哪些信息,再让这些认识去指导实际决策。