跳转至

UB-Mesh Architecture

导言

训练万亿参数模型时,几千甚至上万张 NPU/GPU 不是各算各的。每一步训练都会反复交换梯度、激活和专家 token,网络就像一座每秒要分拣海量包裹的城市:包裹搬得慢,昂贵的计算卡只能停下来等路。

UB-Mesh 的关键想法不是发明一条“无限快”的网线,而是承认通信具有局部性:把最频繁、最大量的通信放到近处的短链路,把较少的远程通信留给远层网络,再让路由、集合通信和容错都理解这张不对称的地图。

先看结论

如果只记住三件事,可以记住:

  1. UB-Mesh 是软硬件协同的网络架构,不是一种新交换机。 它把拓扑、互联操作、路由、集合通信、并行映射和故障接管放在一起设计。
  2. 它用“不对称”换成本。 近处链路多而快,远处链路少而慢;前提是软件真的能把高频通信留在近处。
  3. 论文数字很亮眼,但不是开箱即复现的公开基准。 97% 流量比例来自内部 MoE-2T 工作负载,性能来自与真实 PoC 对齐的内部仿真,成本和可靠性也使用内部价格或估算参数。

可以把五个机制想成一套物流系统:

  • nD-FullMesh 决定仓库和道路怎么建;
  • Unified Bus 统一寄件单和调度接口;
  • APR 在拥堵或断路时选择可用路线;
  • 拓扑感知集合通信 把大批货拆给多条路并行运输;
  • 64+1 在一个分拣台坏掉时让备用台接管。

为什么万卡网络不能只堆交换机

传统 AI 服务器常见两层互联:

  • 服务器内部由 NVLink 一类高带宽互联连接加速卡;
  • 服务器之间经 PCIe、网卡和 InfiniBand/RoCE 进入 Clos 网络。

这种设计成熟、对称、容易理解,却会形成多个“协议岛”。规模变大后,高阶交换机、网卡、光模块和跨域协议转换一起增加;更麻烦的是,训练流量并不均匀。同一个张量并行组或序列并行组内的卡会频繁通信,而隔着多个机架的卡可能很少直接交换数据。

用快递分拣站解释 AI 集群通信局部性
认知锚点:大而频繁的“包裹”尽量在近处短链路循环,少量远程流量再走长链路。长链路没有消失,只是不再为所有方向配置同样带宽。

论文在一个内部 MoE-2T 工作负载中统计到:TP 与 SP 流量合计约占 97%。这个数字能支持“该工作负载存在很强局部性”,却不能推出“任何模型都是 97%”。Dense 模型、不同专家放置、不同并行度和长上下文都会改变通信矩阵。

因此,UB-Mesh 的出发点可以写成:

\[ \text{通信需求矩阵} \longrightarrow \text{分层物理拓扑} \longrightarrow \text{并行与路由映射}. \]

它不是单纯增加总带宽,而是让带宽的位置更匹配流量的位置

nD-FullMesh:先把高频邻居拉近

问题。 非阻塞 Clos 为任意端点对提供较对称的路径,工程上很通用,但也意味着大量流量必须经过交换层和光链路。若大部分通信只发生在固定小组内,处处对称会把钱花在很少使用的方向。

直觉。 把物理距离拆成多个维度:板内、机架内、Pod 内和 Pod 外。近层使用更密的直连和更高带宽,远层逐级降低带宽或继续使用 Clos/DCN。论文把这种递归结构称为 nD-FullMesh

nD-FullMesh 机制五视图
nD-FullMesh 五视图:物理前后、因果逻辑、执行流程、组件生命周期和张量分片数据流。图中对象名是教学规范化表示,不是公开源码接口。

论文 Figure 4 给出了递归逻辑形式:较小 FullMesh 组成更高维的 FullMesh,并用距离层级约束每一维的带宽。

UB-Mesh 论文 Figure 4 nD-FullMesh 逻辑拓扑
论文 Figure 4 原图裁剪:nD-FullMesh 的逻辑拓扑。它说明递归结构,不等于公开了产品的端口、线缆和布线清单。来源:arXiv:2503.20377v3。

对象上,可以把拓扑写成 G=(V,E,d,bw,lat)V 是 NPU、LRS、HRS 等节点,E 是链路,d 是距离层级,bwlat 分别是带宽与延迟。训练画像形成通信需求 C[u,v],表示端点 uv 每步要交换多少字节。

下面是完整的规范化映射伪代码。它表达论文的设计过程,不对应某个公开框架函数:

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 资源的统一发现与访问。

它统一的是操作和控制入口,不是把短电缆、长光纤、交换层和物理延迟变成同一种东西。

Unified Bus 机制五视图
Unified Bus 五视图:统一描述符进入 UB IO 控制器,再由实际 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)不把“最短”当成唯一目标,而是综合路径长度、负载和故障状态。论文公开了三块机制:

  1. Source Routing:源端把路径信息编码进 8 字节 H_SR
  2. 结构化寻址:利用规则拓扑做分段和线性查找;
  3. 无死锁控制:使用两个 Virtual Lane 约束通道依赖。
APR 自适应包路由机制五视图
APR 五视图:控制面选择多路径并把 Source Routing 信息附在包上,链路故障时重映射。绕路是否更快取决于拥堵、路径权重和死锁控制。
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 这类高频通信映射到近层。
拓扑感知集合通信机制五视图
拓扑感知集合通信五视图:逻辑 collective 被切成 chunk,映射到多环或 X/Y 路径,最后 Reduce 或 Concat。chunk 的物理存储和缓冲复用取决于实现。
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 卡的逻辑形状。

64+1 NPU 容错机制五视图
64+1 五视图:论文明确公开的是故障隔离、备用激活和路径重定向;训练状态如何同步到备用卡没有展开,因此在流程中用虚线标出。

下面的伪代码故意把缺口写成必需接口,而不是假装论文已经解决:

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 进行比较。可以把结论分成四类:

  1. 性能。 Figure 17 中,选定的机架内工作负载达到非超卖 Clos 的约 93.2%–95.9%;Figure 19 的跨机架结果在启用 Detour/Borrow 等机制后也接近 Clos,其中 GPT4-2T 的差距报告为 0.46%
  2. 规模线性。 论文报告大模型在 64 NPU 上超过 95% 的线性度。若 L64 是 64 卡时的每卡性能,L1 是单卡性能,则

    \[ \eta_{\text{linear}}=\frac{L_{64}}{L_1}. \]
  3. 成本。 Figure 21 的内部归一化模型中,4D-FullMesh 加 ×4 Clos 相对 ×64 Clos 报告了 2.46× 的 CapEx reduction,即前者约为后者的 1/2.46;论文还报告 98% HRS 和 93% 光模块节省。

  4. 成本效率与可靠性。 论文报告 2.04× 系统成本效率、35% OpEx 降低,以及 98.5 h MTBF、98.8% 可用性。后两者基于组件故障统计估算和 75 min MTTR 假设。
UB-Mesh 论文 Figure 21 归一化 CapEx 对比
论文 Figure 21 原图裁剪:归一化 CapEx 对比。它支持“在论文内部成本模型中更省”,不能替代公开 BOM、采购报价或不同地区的 TCO 计算。来源:arXiv:2503.20377v3。

论文的成本效率可以概括为:

\[ \eta_{\text{cost}} = \frac{P_{\text{avg}}} {C_{\text{capex}}+C_{\text{opex}}}, \]

其中 P_avg 是选定工作负载的平均归一化性能,C_capex 是一次性建设成本,C_opex 是运营成本。稳态可用性常用近似为:

\[ A=\frac{MTBF}{MTBF+MTTR}, \]

其中 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 卡逻辑形状 备用卡、路由与训练状态 不自动保证状态一致 管控、路由、训练框架、状态服务

这五项存在严格依赖:

  1. 没有通信画像,nD-FullMesh 不知道哪里该配置高带宽;
  2. 没有统一控制和路由,分层拓扑难以灵活使用;
  3. 没有拓扑感知 collective,训练仍可能把流量错误地推向远层;
  4. 没有训练状态契约,64+1 只能恢复“通路”,不能证明恢复“正确训练”。

关于峰值显存

这篇论文讨论的是网络架构,不是显存优化。五个机制会引入路由头、表项、描述符、包缓冲、chunk 工作区或备用状态,但没有公开框架实现和配置,无法给出统一可复现的峰值 HBM 数字。任何“显存更省”或“显存只增加 X%”的说法都需要额外实现证据。

小白学习路线与常见误区

建议按下面顺序学习:

  1. 先理解 Collective。 知道 AllReduce 是让所有 rank 得到规约结果,All2All 是每个 rank 向所有其他 rank 交换分片。
  2. 再理解并行组。 TP、SP、EP 为什么会形成不同通信邻居。
  3. 然后看拓扑。 区分板内、机架内、Pod 内和数据中心网络。
  4. 最后看软硬件协同。 同一张拓扑图如何影响放置、路由、通信算法和容错。

常见误区包括:

  • 误区一:FullMesh 就是所有卡永远两两直连。 nD-FullMesh 是递归、分层的局部 FullMesh;高层仍可使用 LRS、HRS 或 Clos。
  • 误区二:Unified Bus 会消灭 RDMA、PCIe 和光纤。 它强调统一接口和控制,底层物理介质与工程约束仍然存在。
  • 误区三:多路径一定更快。 小消息、低负载或调度不佳时,多路径的头部、同步和重排开销可能得不偿失。
  • 误区四:备用卡接管后训练自然正确。 路由恢复只是必要条件;模型、优化器、RNG、数据游标和调度状态必须来自同一个一致点。

总结

UB-Mesh 最值得学习的不是某个孤立数字,而是一种系统设计方法:

先测量通信发生在哪里,再让物理拓扑、控制语义、路由、集合通信和容错共同服从这个事实。

它用局部高带宽和远层低带宽替代处处对称,以降低交换与光互联成本;同时依靠 Unified Bus、APR、拓扑感知 collective 和 64+1 把不对称拓扑变成可用系统。

对小白而言,判断类似架构时可以连续追问五个问题:

  1. 流量局部性来自哪些模型与并行配置?
  2. 省掉了哪些物理部件,又增加了哪些控制状态?
  3. 软件如何知道并利用拓扑?
  4. 性能、成本和可靠性数字来自实测、仿真还是估算?
  5. 故障后恢复的是网络连接,还是完整训练语义?

能回答这五个问题,就不只是在记 UB-Mesh,而是在学习如何读一篇 AI Infra 系统论文。

参考资料

  1. 知返,UB-Mesh: 基于统一互联和高维直连拓扑的AI集群架构,2025。
  2. Jianping Wu et al., UB-Mesh: a Hierarchically Localized nD-FullMesh Datacenter Network Architecture, arXiv:2503.20377v3, 2025。
  3. Jianping Wu et al., UB-Mesh, IEEE Micro, 45(5):20-29, 2025。

评论