Fat-Tree 与 Rail-Optimized 拓扑
GPU 集群的网络拓扑不是"接上就行",接错了 AllReduce 直接掉一半带宽。
学完这节你能做到
- 画出两层 Fat-Tree 并算出它的无阻塞条件
- 解释 rail-optimized 布线为什么能让同 rail 通信只走一跳
- 说清 NVLink 域与网络域的边界在哪
为什么拓扑是这一层最贵的错误
后面那些错误都能改:GID 选错改参数、PCIe 插错换槽位、驱动版本不对重装。 布线错了要停机重接——而且它在账面上完全看不出来。所以拓扑要在动手之前先想清楚。
这一节讲两件事:Fat-Tree 为什么成了标准,以及 rail-optimized 到底优化了什么。
Fat-Tree:把带宽往上堆
传统树形网络越往上越窄,根节点是瓶颈。Fat-Tree 的思路是每往上一层, 总带宽保持不变——靠增加并行链路而不是提高单链路速率。
spine spine spine spine
│ ╲ ╱ │ ╲ ╱ │ │
│ ╳ │ ╳ │ │ 每台 leaf 都连到每台 spine
│ ╱ ╲ │ ╱ ╲ │ │
leaf-0 leaf-1 leaf-2 leaf-3
┌──┴──┐ ┌──┴──┐
node node node node
两层 Fat-Tree 的跳数很好记:
| 通信双方 | 路径 | 跳数 |
|---|---|---|
| 同一台 leaf 下 | leaf | 1 跳 |
| 不同 leaf | leaf → spine → leaf | 3 跳 |
无阻塞的条件就是规划那节的算法: 交换机端口对半分,一半下行接节点、一半上行接 spine。
64 口交换机 → 32 口下行 + 32 口上行
下行容量 = 32 × 400 Gbps = 上行容量 ✓
以太网规划 那节说通用业务 2:1 到 3:1 可接受。 计算网不行,原因是通信模式完全不同:
AllReduce 是全员同时满速通信。 没有"平均利用率"这回事——所有 GPU 在同一时刻互发数据, 上行一旦收敛,所有卡一起等最慢的那条链路。
所以计算网只有 1:1 一个选项。这也是它贵的原因。
Rail:把"哪张卡接哪台交换机"定下来
8 卡节点有 8 张计算网卡。接法有两种,端口数完全一样,性能差一倍。
错误接法:一台机器的卡全接一台 leaf
leaf-0 ← node-0 的 NIC0..NIC7(8 根)
leaf-1 ← node-1 的 NIC0..NIC7(8 根)
看起来很整齐,线也短。问题是:node-0 的任何一张卡要和 node-1 通信, 都必须上 spine——因为它们挂在不同的 leaf 上。
正确接法:rail-optimized
每台机器的第 N 张卡,接到第 N 组 leaf。 这一组就叫一个 rail:
rail 0 rail 1 rail 7
┌────────┐ ┌────────┐ ┌────────┐
│ leaf-0 │ │ leaf-1 │ ... │ leaf-7 │
└───┬────┘ └───┬────┘ └───┬────┘
node-0 ──NIC0┘ NIC1─┘ NIC7─┘
node-1 ──NIC0┘ NIC1─┘ NIC7─┘
...
node-30 ─NIC0┘ NIC1─┘ NIC7─┘
收益来自 NCCL 的通信模式:Ring AllReduce 可以安排成"每张卡只和其它节点的同号卡通信"。
GPU0 ↔ GPU0' 走 rail 0,同一台 leaf,1 跳
GPU1 ↔ GPU1' 走 rail 1,同一台 leaf,1 跳
...
于是绝大部分流量只走一跳,根本不上 spine。spine 只承担跨 rail 的少量流量。
| 卡全接一台 leaf | rail-optimized | |
|---|---|---|
| 端口数 | 相同 | 相同 |
| 交换机台数 | 相同 | 相同 |
| 线缆数 | 相同 | 相同 |
| 同号卡通信跳数 | 3 跳(必过 spine) | 1 跳 |
| spine 压力 | 全部流量 | 少量跨 rail 流量 |
| AllReduce 带宽 | 约一半 | 满 |
这是本站反复强调的那类错误:端口总数、交换机台数、线缆数、验收单全都对得上, 唯一的差别是"哪根线插在哪个口"。
发现它只有一个办法:实测 busbw。所以 GPU 集群交付必须把 「busbw ≥ 理论峰值 90%」写进验收条款——这个数字是唯一能一次性覆盖 布线、拓扑、配置和拥塞控制的端到端指标。
核对实际接线用 IB 的拓扑导出:
ibnetdiscover > topo.txt
# 看每台交换机下挂了哪些节点的哪张卡
grep -A40 '^Switch.*leaf-0' topo.txt理想情况下 leaf-0 下面应该是一堆不同节点的同号卡,而不是同一个节点的多张卡。
SU:按整单元布线
SuperPOD 参考架构 把 32 个节点定义为一个 SU(scalable unit),这个数字不是随便取的:
64 口交换机 ÷ 2 = 32 口下行
每个节点在一个 rail 上占 1 口
→ 一台 leaf 正好接 32 个节点 = 1 个 SU
组件数量随 SU 线性增长(这张表 规划那节 的计算器能算出来):
| SU | 节点 | GPU | leaf | spine | 计算+UFM 线缆 | spine-leaf 线缆 |
|---|---|---|---|---|---|---|
| 1 | 31 | 248 | 8 | 4 | 252 | 256 |
| 2 | 63 | 504 | 16 | 8 | 508 | 512 |
| 3 | 95 | 760 | 24 | 16 | 764 | 768 |
| 4 | 127 | 1016 | 32 | 16 | 1020 | 1024 |
两个值得记住的细节:
① 32 个机位只装 31 台机器——腾一个位置给 UFM
(InfiniBand 那节 讲的管理平面)接线。
这也是"计算+UFM 线缆"比 节点 × 8 多 4 根的原因。
② 不满一个 SU 也要按整 SU 布线。 参考架构的原话是:即使节点数少于一个 SU, 也要把整个 SU 的 leaf 和 leaf-spine 链路都接完,空位留着不插机器。
因为路径长度要一致。如果按实际机器数缩减布线,不同位置的节点之间跳数会不同, 于是"性能取决于机器插在哪台 leaf 上"——这在调度器随机分配节点的集群里是灾难: 同一个训练任务,这次跑得快、下次跑得慢,而且找不到原因。
留空位的成本是几台交换机和一批线缆;不留的成本是永久性的性能不确定性。
NVLink 域与网络域的边界
这是最后一块拼图。NVLink 那节 讲过带宽层级, 这里把它和拓扑对齐:
┌────────── NVLink 域(机内,8 卡或 NVL72 的 72 卡)──────────┐
│ GPU ↔ GPU:450 GB/s 单向,NVSwitch 全互联,不经过 leaf │
└──────────────────────┬──────────────────────────────────────┘
│ 每 GPU 一张 400G 网卡(PCIe Gen5 x16)
▼
┌───────── 机间网络(rail-optimized Fat-Tree)─────────┐
│ 同 rail 1 跳 50 GB/s 单向 / 跨 rail 3 跳 │
└──────────────────────────────────────────────────────┘
规划时两笔账分开算:
| 谁决定 | 你能改吗 | |
|---|---|---|
| 机内(NVLink 域大小) | 服务器型号(HGX 8 卡 / NVL72) | 只能选机型 |
| 机间(rail / leaf / spine) | 你的布线 | 能,而且必须算对 |
并行策略要贴着这个边界走:张量并行留在 NVLink 域内(通信最重), 数据并行和流水线并行跨机。NVL72 把域从 8 扩到 72 的意义就是让 TP 度数能开更大。
检查点
8 卡节点、64 口交换机、rail-optimized。node-0 的 GPU3 要和 node-5 的 GPU3 通信,走几跳?
某集群端口数、交换机台数、线缆数与设计完全一致,但 AllReduce 只有理论值一半。最可能的原因?
只买了 16 台节点(半个 SU),为什么参考架构仍建议把整个 SU 的 leaf 与 leaf-spine 链路接完?
这节课的落点
- Fat-Tree 靠并行链路保持每层总带宽;两层拓扑只有 1 跳(同 leaf)或 3 跳(过 spine)
- 无阻塞 = 交换机端口对半分;计算网没有收敛比可讨论,因为 AllReduce 是全员同时满速
- rail = 每台机器的第 N 张卡接到第 N 组 leaf,让同号卡通信只走 1 跳
- 接错 rail 时端口数、台数、线缆数全对,只有实测 busbw 能发现
- 用
ibnetdiscover核对:一台 leaf 下应该是不同节点的同号卡 - 1 SU = 32 节点(源于 64 口 ÷ 2),但只装 31 台,留一位给 UFM
- 不满一个 SU 也按整 SU 布线,为的是路径长度一致、性能可预期
- 规划分两笔账:机内 NVLink 域由机型决定,机间 rail/leaf/spine 由你的布线决定