UB-Mesh Architecture
导言
训练万亿参数模型时,几千甚至上万张 NPU/GPU 不是各算各的。每一步训练都会反复交换梯度、激活和专家 token,网络就像一座每秒要分拣海量包裹的城市:包裹搬得慢,昂贵的计算卡只能停下来等路。
UB-Mesh 的关键想法不是发明一条“无限快”的网线,而是承认通信具有局部性:把最频繁、最大量的通信放到近处的短链路,把较少的远程通信留给远层网络,再让路由、集合通信和容错都理解这张不对称的地图。
先看结论¶
如果只记住三件事,可以记住:
- UB-Mesh 是软硬件协同的网络架构,不是一种新交换机。 它把拓扑、互联操作、路由、集合通信、并行映射和故障接管放在一起设计。
- 它用“不对称”换成本。 近处链路多而快,远处链路少而慢;前提是软件真的能把高频通信留在近处。
- 论文数字很亮眼,但不是开箱即复现的公开基准。
97%流量比例来自内部 MoE-2T 工作负载,性能来自与真实 PoC 对齐的内部仿真,成本和可靠性也使用内部价格或估算参数。
可以把五个机制想成一套物流系统:
- nD-FullMesh 决定仓库和道路怎么建;
- Unified Bus 统一寄件单和调度接口;
- APR 在拥堵或断路时选择可用路线;
- 拓扑感知集合通信 把大批货拆给多条路并行运输;
- 64+1 在一个分拣台坏掉时让备用台接管。
为什么万卡网络不能只堆交换机¶
传统 AI 服务器常见两层互联:
- 服务器内部由 NVLink 一类高带宽互联连接加速卡;
- 服务器之间经 PCIe、网卡和 InfiniBand/RoCE 进入 Clos 网络。
这种设计成熟、对称、容易理解,却会形成多个“协议岛”。规模变大后,高阶交换机、网卡、光模块和跨域协议转换一起增加;更麻烦的是,训练流量并不均匀。同一个张量并行组或序列并行组内的卡会频繁通信,而隔着多个机架的卡可能很少直接交换数据。
论文在一个内部 MoE-2T 工作负载中统计到:TP 与 SP 流量合计约占 97%。这个数字能支持“该工作负载存在很强局部性”,却不能推出“任何模型都是 97%”。Dense 模型、不同专家放置、不同并行度和长上下文都会改变通信矩阵。
因此,UB-Mesh 的出发点可以写成:
它不是单纯增加总带宽,而是让带宽的位置更匹配流量的位置。
nD-FullMesh:先把高频邻居拉近¶
问题。 非阻塞 Clos 为任意端点对提供较对称的路径,工程上很通用,但也意味着大量流量必须经过交换层和光链路。若大部分通信只发生在固定小组内,处处对称会把钱花在很少使用的方向。
直觉。 把物理距离拆成多个维度:板内、机架内、Pod 内和 Pod 外。近层使用更密的直连和更高带宽,远层逐级降低带宽或继续使用 Clos/DCN。论文把这种递归结构称为 nD-FullMesh。
论文 Figure 4 给出了递归逻辑形式:较小 FullMesh 组成更高维的 FullMesh,并用距离层级约束每一维的带宽。
对象上,可以把拓扑写成 G=(V,E,d,bw,lat):V 是 NPU、LRS、HRS 等节点,E 是链路,d 是距离层级,bw 和 lat 分别是带宽与延迟。训练画像形成通信需求 C[u,v],表示端点 u 与 v 每步要交换多少字节。
下面是完整的规范化映射伪代码。它表达论文的设计过程,不对应某个公开框架函数:
def build_locality_aware_mapping(ranks, collectives, topology, link_capacity):
demand = {(src, dst): 0 for src in ranks for dst in ranks}
for collective in collectives:
for transfer in expand_collective_into_transfers(collective):
key = (transfer.src, transfer.dst)
demand[key] += transfer.bytes_per_step
groups = infer_parallel_groups(collectives)
groups = sorted(groups, key=lambda group: group.bytes_per_step, reverse=True)
placement = {}
unused_nodes = set(topology.compute_nodes)
for group in groups:
candidates = enumerate_connected_subsets(
nodes=unused_nodes,
size=group.rank_count,
topology=topology,
)
if not candidates:
raise RuntimeError("no connected subset can host the parallel group")
best = min(
candidates,
key=lambda subset: weighted_distance_cost(
group=group,
subset=subset,
demand=demand,
topology=topology,
),
)
placement[group.id] = bind_ranks(group.ranks, best)
unused_nodes.difference_update(best)
routes = derive_routes(placement, topology)
if not routes_fit_capacity(routes, demand, link_capacity):
raise RuntimeError("mapped traffic exceeds one or more link capacities")
return placement, routes
适用与代价。
- 适合通信组稳定、TP/SP/EP 结构可画像、机架与 Pod 能按训练组分配的集群。
- 不适合直接照搬通信图频繁变化、任意两卡都需要同等带宽、租户碎片化严重的场景。
- 直接收益对象是 HRS、光模块和远层带宽配置;它不直接减少模型参数或激活显存。
- 新增状态是拓扑图、通信画像、放置和路由表。论文没有给出可复现的峰值 HBM 变化,不能声称“省网络就一定省显存”。
- 实现归属横跨机框布线、交换硬件、集群资源调度器和训练并行规划器;它不是只改一个集合通信算子就能获得的收益。
Unified Bus:统一控制,而非抹平距离¶
问题。 CPU 到 NPU、NPU 到 NPU、跨服务器通信可能分别落在 PCIe、专用 Scale-Up 互联和 IB/RoCE 上。上层不仅要认识不同设备,还要适配不同地址、操作和完成语义。
直觉。 Unified Bus(UB)提供统一互联的操作与 IO 控制层。论文公开的接口意图包括:
- 同步
Load / Store / Atomic; - 异步
Read / Write / Message; - CPU、NPU、内存和 Fabric 资源的统一发现与访问。
它统一的是操作和控制入口,不是把短电缆、长光纤、交换层和物理延迟变成同一种东西。
一个教学化描述符 D_UB 可以包含 op、目标地址、长度、同步模式和权限。地址映射 M_addr 跨操作复用,完成事件 E_complete 则只存活到本次请求结束。
def submit_unified_bus_operation(controller, address_map, operation):
required = {"opcode", "target_id", "offset", "length", "mode", "permission"}
if set(operation.keys()) != required:
raise ValueError("operation fields do not match the normalized UB contract")
endpoint = address_map.resolve(operation["target_id"])
if not endpoint.permission_allows(operation["permission"], operation["opcode"]):
raise PermissionError("operation is not permitted for this endpoint")
descriptor = encode_descriptor(
opcode=operation["opcode"],
address=endpoint.base_address + operation["offset"],
length=operation["length"],
completion_mode=operation["mode"],
)
route = controller.select_fabric_route(endpoint, operation["length"])
completion = controller.issue(descriptor, route)
if operation["mode"] == "synchronous":
result = completion.wait()
if not result.ok:
raise IOError(result.error)
return result
return completion
适用与代价。
- 适合异构计算与内存资源池、希望统一设备发现和操作语义的平台。
- 收益主要是减少上层协议分叉、复用寻址与控制器,并给拓扑路由留下统一入口;不是保证每次读写更低延迟。
- 代价是控制器、地址空间、权限、错误语义和生态兼容都要共同成熟。
- 缓存与显存方面会存在描述符、映射、包和完成状态,但公开材料不足以给出可复现的峰值公式。
- 实现归属是互联协议、IO 控制器、固件、驱动和运行时。论文没有发布完整 UB ABI,伪代码只能说明契约,不能冒充现成 API。
APR:绕路有时更快¶
问题。 最短路径可能正在拥堵,而旁边的非最短路径却空着;某条链路故障后,静态路由还可能让整个通信组停住。
直觉。 Adaptive Packet Routing(APR)不把“最短”当成唯一目标,而是综合路径长度、负载和故障状态。论文公开了三块机制:
- Source Routing:源端把路径信息编码进 8 字节
H_SR; - 结构化寻址:利用规则拓扑做分段和线性查找;
- 无死锁控制:使用两个 Virtual Lane 约束通道依赖。
def route_packet_with_apr(packet, route_table, telemetry, failed_links):
candidates = []
for route in route_table.lookup(packet.source, packet.destination):
if any(link in failed_links for link in route.links):
continue
if not route.satisfies_virtual_lane_rules():
continue
score = (
route.hop_count
+ telemetry.queue_penalty(route)
+ telemetry.utilization_penalty(route)
)
candidates.append((score, route))
if not candidates:
raise ConnectionError("no deadlock-safe route is available")
candidates.sort(key=lambda item: item[0])
selected_route = candidates[0][1]
header = encode_source_route(selected_route, byte_length=8)
forwarded_packet = attach_header(packet, header)
for hop in selected_route.hops:
result = hop.forward(forwarded_packet)
if not result.ok:
route_table.mark_unavailable(result.failed_link)
return route_packet_with_apr(
packet=packet,
route_table=route_table,
telemetry=telemetry,
failed_links=failed_links | {result.failed_link},
)
return forwarded_packet.completion()
适用与代价。
- 适合规则、多路径丰富且有实时链路状态的拓扑。
- 收益是提高空闲链路利用率、在局部故障时继续转发;它不保证每个绕路都比最短路快。
- 代价包括 8 字节头、路由表、遥测、权重更新和 Virtual Lane 资源。
H_SR随包产生并在包完成后释放;路由表跨多个包持久存在。包缓冲和在途深度会影响内存,但论文没有公开可复现配置。- 实现归属是路径控制器、NPU/交换转发逻辑、固件与网络管控面。论文没有公开权重算法和完整故障收敛实现。
拓扑感知集合通信:让算法配合道路¶
问题。 有了分层拓扑,如果集合通信仍把所有数据塞进一条逻辑环,或者并行组随意跨越远层,硬件省下的链路会变成软件制造的拥堵。
直觉。 先按物理拓扑拆分张量和通信阶段,再让多个互不冲突的路径并行:
- AllReduce 使用 Multi-Ring,把不同 chunk 分给多条环;
- All2All 可沿 X/Y 多路径并行,或使用分层 Broadcast/Reduce;
- 并行策略搜索优先把 TP/SP 这类高频通信映射到近层。
def execute_topology_aware_collective(tensor, collective, topology, ranks):
if collective.kind == "all_reduce":
paths = build_nonconflicting_rings(topology, ranks)
combine = reduce_sum
elif collective.kind == "all_to_all":
paths = build_xy_or_hierarchical_paths(topology, ranks)
combine = concatenate_by_destination
else:
raise ValueError("unsupported collective kind")
if not paths:
raise RuntimeError("no valid collective path is available")
chunks = split_tensor(tensor, count=len(paths), axis=collective.split_axis)
handles = []
for chunk, path in zip(chunks, paths):
handle = launch_collective_chunk(
chunk=chunk,
path=path,
operation=collective.kind,
)
handles.append(handle)
partials = []
for handle in handles:
result = handle.wait()
if not result.ok:
for pending in handles:
pending.cancel_if_possible()
raise IOError(result.error)
partials.append(result.tensor)
output = combine(partials)
release_chunks(chunks)
release_partials_except_output(partials, output)
return output
适用与代价。
- 适合集合通信库能获得拓扑、链路容量和并行组信息的固定集群。
- 收益直接体现在链路利用率和重叠机会;最终训练吞吐还取决于计算、同步、chunk 大小和调度开销。
-
代价是拆分、多个 in-flight handle、局部 partial 和最终合并。峰值通信工作区可粗略写成
\[ M_{\text{comm}} \approx M_X +\sum_{j=1}^{k}M_{X_j,\text{materialized}} +M_{\text{workspace}} +M_{\text{inflight}}, \]其中
M_X是原张量字节数,k是路径或环数量,M_{X_j,materialized}只统计真正复制而非 view 的 chunk,M_workspace是 Reduce/Concat 工作区,M_inflight是在途包和描述符。论文没有公开这些实现量,因此不能把该式算成统一的峰值数字。 -
实现归属是训练并行规划器、集合通信库、CCU/通信硬件和运行时调度器。论文给出算法方向,没有发布独立通信微基准的完整复现配置。
64+1:用一张备用卡保住训练形状¶
问题。 一个机架有 64 张卡时,单卡不可恢复故障可能迫使整个并行组降到 63 卡,甚至重启作业。训练的张量形状、并行度和通信拓扑往往不能自然接受“少一张”。
直觉。 每 64 张工作 NPU 配一张备用 NPU B。论文示意:NPU-3 故障后激活 B,并把原来 5→3 的路径改成 5→LRS→B。这多一跳,却保住了 64 卡的逻辑形状。
下面的伪代码故意把缺口写成必需接口,而不是假装论文已经解决:
def fail_over_one_npu(rack, failed_npu, standby_npu, state_provider):
rack.control_plane.isolate(failed_npu)
if not rack.control_plane.health_check(standby_npu):
raise RuntimeError("standby NPU is not healthy")
rack.control_plane.activate(standby_npu)
logical_rank = rack.rank_map.rank_of(failed_npu)
snapshot = state_provider.latest_consistent_state(logical_rank)
required_fields = {
"model_parameters",
"optimizer_state",
"rng_state",
"data_cursor",
"scheduler_state",
}
if snapshot is None or not required_fields.issubset(snapshot.keys()):
raise RuntimeError("no complete consistent training state is available")
state_provider.restore(standby_npu, snapshot)
rack.rank_map.replace(logical_rank, standby_npu)
rack.route_table.redirect_destination(
old_endpoint=failed_npu,
new_endpoint=standby_npu,
via=rack.low_radix_switch,
)
if not rack.run_collective_health_probe():
raise RuntimeError("collective probe failed after route update")
rack.training_runtime.resume(logical_rank)
return standby_npu
这里 state_provider 是文章补出的系统契约,不是论文公开组件。它必须提供一致的参数、优化器、随机数、数据游标和调度器状态;否则,“网络重新连通”不等于“训练语义正确”。
适用与代价。
- 适合单卡故障比整机故障更常见、训练并行度要求稳定、备用成本可接受的机架。
- 收益是保持逻辑 rank 数和通信形状,并缩小单 NPU 故障的爆炸半径。
- 代价是一张备用卡、故障后的额外一跳、状态复制或恢复带宽,以及更复杂的控制面。
- 内存边界取决于备用卡是热备、温备还是从一致快照恢复。论文没有给出状态同步协议,因此不能计算备用 HBM 峰值或恢复时间。
- 实现归属横跨机架管控、路由、训练框架、Checkpoint/状态服务和数据加载器。
论文结果到底说明了什么¶
论文把 UB-Mesh 与不同超卖倍率的 Clos 进行比较。可以把结论分成四类:
- 性能。 Figure 17 中,选定的机架内工作负载达到非超卖 Clos 的约
93.2%–95.9%;Figure 19 的跨机架结果在启用 Detour/Borrow 等机制后也接近 Clos,其中 GPT4-2T 的差距报告为0.46%。 -
规模线性。 论文报告大模型在 64 NPU 上超过
95%的线性度。若L64是 64 卡时的每卡性能,L1是单卡性能,则\[ \eta_{\text{linear}}=\frac{L_{64}}{L_1}. \] -
成本。 Figure 21 的内部归一化模型中,4D-FullMesh 加
×4Clos 相对×64Clos 报告了2.46×的 CapEx reduction,即前者约为后者的1/2.46;论文还报告98%HRS 和93%光模块节省。 - 成本效率与可靠性。 论文报告
2.04×系统成本效率、35%OpEx 降低,以及98.5 hMTBF、98.8%可用性。后两者基于组件故障统计估算和75 minMTTR 假设。
论文的成本效率可以概括为:
其中 P_avg 是选定工作负载的平均归一化性能,C_capex 是一次性建设成本,C_opex 是运营成本。稳态可用性常用近似为:
其中 MTBF 是平均故障间隔,MTTR 是平均修复时间。
正确读法
这些结果说明 UB-Mesh 在论文设定的负载、拓扑、仿真器和成本参数下具有很强潜力。它们不是公开原始日志,也没有完整 BOM、仿真代码、训练配置和长期舰队故障数据。因此,不应把 2.46× 或 98.8% 当作换一批硬件仍自动成立的常数。
五个机制如何协作¶
| 机制 | 主要改什么 | 直接收益 | 新增状态或工作区 | 不改变什么 | 主要归属 |
|---|---|---|---|---|---|
| nD-FullMesh | 物理拓扑与带宽层级 | 少走高阶交换和光链路 | 拓扑、放置、路由表 | 远程通信仍存在 | 机框、网络、调度器 |
| Unified Bus | 操作与 IO 控制入口 | 减少协议分叉,统一寻址 | 描述符、映射、完成状态 | 物理距离和链路能力 | 协议、控制器、驱动、运行时 |
| APR | 包级路径选择 | 利用空闲路径和故障绕行 | 8B SR 头、权重、遥测、VL | 绕路不一定更快 | 固件、转发、控制面 |
| 拓扑感知集合通信 | tensor chunk 与路径调度 | 多环/多轴并行 | chunk、partial、in-flight handle | 计算和同步开销仍在 | 并行规划器、通信库、CCU |
| 64+1 | 单 NPU 故障接管 | 保留 64 卡逻辑形状 | 备用卡、路由与训练状态 | 不自动保证状态一致 | 管控、路由、训练框架、状态服务 |
这五项存在严格依赖:
- 没有通信画像,nD-FullMesh 不知道哪里该配置高带宽;
- 没有统一控制和路由,分层拓扑难以灵活使用;
- 没有拓扑感知 collective,训练仍可能把流量错误地推向远层;
- 没有训练状态契约,64+1 只能恢复“通路”,不能证明恢复“正确训练”。
关于峰值显存
这篇论文讨论的是网络架构,不是显存优化。五个机制会引入路由头、表项、描述符、包缓冲、chunk 工作区或备用状态,但没有公开框架实现和配置,无法给出统一可复现的峰值 HBM 数字。任何“显存更省”或“显存只增加 X%”的说法都需要额外实现证据。
小白学习路线与常见误区¶
建议按下面顺序学习:
- 先理解 Collective。 知道 AllReduce 是让所有 rank 得到规约结果,All2All 是每个 rank 向所有其他 rank 交换分片。
- 再理解并行组。 TP、SP、EP 为什么会形成不同通信邻居。
- 然后看拓扑。 区分板内、机架内、Pod 内和数据中心网络。
- 最后看软硬件协同。 同一张拓扑图如何影响放置、路由、通信算法和容错。
常见误区包括:
- 误区一:FullMesh 就是所有卡永远两两直连。 nD-FullMesh 是递归、分层的局部 FullMesh;高层仍可使用 LRS、HRS 或 Clos。
- 误区二:Unified Bus 会消灭 RDMA、PCIe 和光纤。 它强调统一接口和控制,底层物理介质与工程约束仍然存在。
- 误区三:多路径一定更快。 小消息、低负载或调度不佳时,多路径的头部、同步和重排开销可能得不偿失。
- 误区四:备用卡接管后训练自然正确。 路由恢复只是必要条件;模型、优化器、RNG、数据游标和调度状态必须来自同一个一致点。
总结¶
UB-Mesh 最值得学习的不是某个孤立数字,而是一种系统设计方法:
先测量通信发生在哪里,再让物理拓扑、控制语义、路由、集合通信和容错共同服从这个事实。
它用局部高带宽和远层低带宽替代处处对称,以降低交换与光互联成本;同时依靠 Unified Bus、APR、拓扑感知 collective 和 64+1 把不对称拓扑变成可用系统。
对小白而言,判断类似架构时可以连续追问五个问题:
- 流量局部性来自哪些模型与并行配置?
- 省掉了哪些物理部件,又增加了哪些控制状态?
- 软件如何知道并利用拓扑?
- 性能、成本和可靠性数字来自实测、仿真还是估算?
- 故障后恢复的是网络连接,还是完整训练语义?
能回答这五个问题,就不只是在记 UB-Mesh,而是在学习如何读一篇 AI Infra 系统论文。
参考资料¶
- 知返,UB-Mesh: 基于统一互联和高维直连拓扑的AI集群架构,2025。
- Jianping Wu et al., UB-Mesh: a Hierarchically Localized nD-FullMesh Datacenter Network Architecture, arXiv:2503.20377v3, 2025。
- Jianping Wu et al., UB-Mesh, IEEE Micro, 45(5):20-29, 2025。