MikroTik CRS812 400G 拆分连到 DGX Spark:200G 链路封顶在 106 Gb/s,NCCL 回落到 Socket
我们正在搭建四个 DGX Spark 节点做分布式训练,全部接在一台 MikroTik CRS812-8DS-2DQ-2DDQ 上。方案是交换机上一个 400G QSFP-DD 端口拆分给两个节点各用 200G,用几根拆分线就能覆盖整个集群。
- MikroTik CRS812-8DS-2DQ-2DDQ,QSFP-DD 端口工作在拆分(breakout)模式
- NADDOD Q2Q56-400G-CU2,QSFP-DD 400G 转 2×QSFP56 200G 无源 DAC
- 板载 ConnectX-7 的 DGX Spark 节点
- 用 iperf3 和 nccl-tests 的 all_reduce_perf 做验证
两端都报告链路是干净的 200GbE,但吞吐量只有一半多一点:
# iperf3 -c <peer> -P 8
[SUM] 0.00-10.00 sec ... 106 Gbits/sec
single stream: ~30 Gbits/sec
# ip -br link
enp1s0f1np1 UP
enP2p1s0f1np1 UP
NCCL 那边看着更糟:all_reduce_perf 显示走的是 Socket 传输,四个节点之间的总线带宽大约只有 2 GB/s,很明显根本没用上 RDMA。
我们已经检查过:
- 在交换机端口之间重新插拔并互换了拆分线,数字一模一样
- 增加了并发流数量,总量依然钉在 106 Gb/s 附近
- 确认交换机报告的端口速率是 200G 而不是 100G
我一直想不通的一点是,一个物理 QSFP56 端口在节点上显示成了两个逻辑接口。是不是这种拆分只把一半的通道分给了每个节点,还是说这款硬件上的 200G 端口本来就应该长这样?
Comments 7
情况正是这样,拆分线是清白的。在这款硬件上,ConnectX-7 端口是通过 PCIe x4 接上去的,会被暴露成两个逻辑半区,每个大约承载 100 Gb/s。只有当两个半区同时都有负载时,才会出现完整的 200G,所以单地址的 iperf3 跑出来刚超过 100 Gb/s 就停住,这是预期结果,不是故障。
下面这些让它跑起来了:
两个半区都跑上流量之后,这对链路应该能接近线速,nccl-tests 的 all_reduce_perf 也会给出完全不同量级的总线带宽,一旦它不再走 Socket。
在怪线缆之前,你到底是怎么驱动那两个接口的?你贴的 enp1s0f1np1 和 enP2p1s0f1np1 都是 UP 状态,但 iperf3 是打到这两个接口都上,还是只打到配了地址的那一个?
还值得贴出来的:节点上和 CRS812 端口上的 MTU 各是多少,因为在这个速率下 1500 会严重拖后腿;以及 /etc/nccl.conf 的内容。NCCL 选择 Socket 传输,几乎总是因为那个文件里有东西告诉它不要碰 IB 路径,而不是因为网络本身坏了。
问得好。只有 enp1s0f1np1 配了地址,enP2p1s0f1np1 那一半是 up 的但没配置,目前所有 iperf3 测试都是打到这一个地址上。节点上 MTU 是 1500,交换机那边的二层 MTU 我也没动过。还真让你说中了:
这是镜像里本来就有的,我从来没怀疑过它。所以那 106 Gb/s 有没有可能就是端口的一半再加上一点余量?
不同的技术栈,但同样形状的意外。我这边是 RHEL 8.4 下的 ConnectX-6(MT28908),MLNX_OFED 5.7,固件 20.32.2004,MFT 4.21;对端是一台 Switch-IB 2 SB7800,中间用一根 LinkX MCP7H50-H002R26 分线缆把 200G 拆成 2×100G。端口协商结果是
无论 mlxlink -d mlx5_0 -p 1 --speeds edr 还是 --speeds hdr 都没有任何变化。后来发现这是芯片本身的一道天花板,而不是配置错误:EDR 器件只能组成 1x 或 4x 宽度的链路,而这种分线缆依赖的是 2x 分组,这个特性是 HDR 才引入的。所以要么用一根普通的 4x EDR 线缆接那台交换机,要么如果非要拆分就得上 HDR。
对所有拆分场景通用的教训是:先搞清楚两端各自实际能组成什么样的通道分组,再去测什么数字。
上面那套方法里有一点值得单独说清楚,因为这是大家最容易把收益又丢回去的地方:交换机上的 MTU 也必须匹配。只在主机上设成 9000,而端口还在按 1500 字节的帧转发,换来的是丢包,不是吞吐量。先在 CRS812 端口上设好二层 MTU,用大负载的 ping 验证一遍,再重新跑测试。
IPv6 那一点也是同样的道理。两个半区都配了地址,再留着 IPv6 不关,每个端口就会多出额外的 GID 条目,你的测试被告知要用的那个索引未必是你以为的那个。在 CX7 接口上关掉 IPv6,能让这张表保持精简和可预测,跨重启都不变——在对比不同测试结果时,这一点比听起来重要得多。
值得留意的是,一个始终起不来的拆分端口,和你遇到的情况完全是两码事。在一台二手的 Arista DCS-7060CX-32S(EOS 4.16.8FX-7060X)上,我的四个子接口完全没有任何报错,就是始终不建立链路。设备当时的配置是 transceiver qsfp default-mode 4x10G,而对端呈现的是 25G,Et17/1 一直停在 errdisabled 状态,直到手动设置速率:
同一次排查里,一根 Mellanox 线缆被当作未认证的收发器拒绝了,只能换成一根 Arista 兼容的 100GBASE-CR4 QSFP28 DAC。走到另一个极端的是一位同事的经历:他在一台跑 Junos 23.2R1-S1.8-EVO 的 QFX5220-32CD 上,始终没能把一根 QDD-4X100G-2P5M 拆分线对接到一台 Mellanox 交换机上跑起来,用了 Port Checker 验证过的端口配置,试遍了每种 FEC 组合都不行。你这边好歹能协商成功还能过流量,已经算好的了。
确认有效,端口本身其实从来没坏过。我把 enP2p1s0f1np1 配成了独立接口,在节点和交换机端口上都设了 MTU 9000,两个 CX7 接口都关掉了 IPv6,也把 NCCL_IB_DISABLE=1 从 /etc/nccl.conf 里删掉了。
现在两个并行的 iperf3 会话,每个半区一个,总量能到 196-198 Gb/s。四个节点跑 all_reduce_perf,总线带宽报告是 23.76 GB/s,NCCL 走的是 RDMA 路径,日志里再也没有 Socket 传输了。NADDOD Q2Q56-400G-CU2 这根线自始至终都没有问题。