1. 先建立一张总图
SGLang 不会自己搬运 16 张 GPU 之间的 Tensor。模型代码发起 TP/MoE 通信, NCCL 决定用什么算法、经过哪条链路把数据送到其他 rank。
NCCL bootstrap 是“启动时要完成的一件事”;
NCCL_SOCKET_IFNAME 是“选择 IP 网卡的一个参数”;
NET/IB 和 NET/Socket 才是 NCCL 实际搬运数据的传输后端。
两类跨机路径
理想路径:RDMA
GPU → HCA → RoCE 网络 → HCA → GPU
日志应出现 NET/IB,支持时还会出现 GDRDMA。
回退路径:TCP Socket
GPU/CPU → Linux Socket → ethX → TCP/IP → ethX
日志会出现 Using network Socket。这不是报错,但性能通常低得多。
2. eth0 和 mlx5_0 不是同一个设备
eth0 是该端口的 Linux netdev/IP 入口;
mlx5_0 是映射到该端口的 RDMA Verbs/HCA 入口。
二者相关联,但不相等,也不代表 TCP 或 RDMA 应用一定能跑到 400G。
| 名字 | 属于哪一层 | 负责什么 | 本机实例 |
|---|---|---|---|
eth0 |
Linux IP 网卡接口 | 配置 IP、TCP/UDP、路由;由 NCCL_SOCKET_IFNAME 选择 |
400 Gbit/s 计算网 |
eth3 |
Linux IP 网卡接口 | 第二条计算网 Rail | 400 Gbit/s 计算网 |
mlx5_0 |
RDMA HCA / Verbs 设备 | 供 NET/IB 使用;由 NCCL_IB_HCA 选择 |
对应 eth0,挂 switch 1 |
mlx5_3 |
RDMA HCA / Verbs 设备 | 第二条 RDMA Rail | 对应 eth3,挂 switch 2 |
/dev/infiniband/uverbs0 |
Linux 字符设备 | 容器进程访问 RDMA Verbs 的入口 | 对应 mlx5_0 |
mlx5_0 port 1 ==> eth0 (Up)
mlx5_3 port 1 ==> eth3 (Up)
同一条物理端口可以同时暴露 Linux IP 接口和 RDMA HCA。
eth0 是 IP/Socket 世界的入口,mlx5_0 是 RDMA
Verbs 世界的入口。ibdev2netdev 输出的是映射关系,不是等号。
本项目部署时只把 eth0/eth3 作为节点间计算网。
同一条 400G 物理 Ethernet 端口
├── eth0 -> Linux netdev -> IP / TCP Socket
└── mlx5_0 -> RDMA HCA -> RoCE / Verbs / GDRDMA
400 Gbit/s = 50 GB/s 只是单方向理论线速。协议开销、PCIe、
CPU、Socket 线程、消息大小和 collective 算法都会让实际
algbw/busbw 低于或采用不同统计口径。
3. 核心术语字典
| 术语 | 通俗解释 | 在本项目中的意义 |
|---|---|---|
| NCCL | NVIDIA 的多 GPU 通信库,负责高效实现 collective 和点对点通信。 | SGLang TP16 每层跨 GPU 通信最终大量落到 NCCL。 |
| rank | 一个通信参与者的编号。TP16 communicator 有 rank 0–15。 | 两台机器各 8 个 GPU rank,共 16 个。 |
| collective | 一组 rank 共同参与的通信操作。 | TP 常见 AllReduce、AllGather、ReduceScatter;MoE 还可能有 AllToAll。 |
| RDMA | 远端直接内存访问。网卡可直接读写远端内存,减少 CPU 和内核数据拷贝。 | 双机 TP16 希望使用的高速数据路径。 |
| IB | InfiniBand。既是一套高速网络体系,也常被 NCCL 用作 Verbs/RDMA 后端的统称。 | NCCL 日志里的 NET/IB 也可承载 RoCE,不代表交换机一定是原生 IB。 |
| RoCE | RDMA over Converged Ethernet,在以太网上承载 RDMA。 | 本项目的 400G 计算网类型。 |
| HCA | Host Channel Adapter,提供 RDMA 能力的适配器。 | mlx5_0、mlx5_3。 |
| GDRDMA | GPUDirect RDMA,让 HCA 直接访问 GPU 显存,减少经 CPU 内存中转。 | 跨机 GPU 通信的理想路径,日志可见 via NET/IB/.../GDRDMA。 |
| Socket / TCP | 普通 IP 网络编程路径。NCCL 找不到 RDMA 时会使用。 | 本次脚本实际发生的回退路径。 |
| Rail | 一条相对独立的网络通道,通常由一张 HCA 和一套交换路径组成。 | mlx5_0/switch 1 与 mlx5_3/switch 2 是双 Rail。 |
| ring / tree | NCCL 对 collective 的通信拓扑组织方式。 | NCCL_CROSS_NIC 决定同一 ring/tree 能否跨不同 NIC。 |
| PFC / ECN | RoCE 网络控制拥塞和丢包的机制。 | RDMA 出现 retry、pause 或吞吐抖动时由运维检查。 |
4. NCCL bootstrap 到底是什么
NCCL 本身不是进程启动器。SGLang 先启动各个 worker,NCCL communicator 初始化时, rank 之间需要交换地址、唯一 ID、拓扑和连接信息,这段“先认识彼此”的过程就是 bootstrap。
- 每个 rank 启动并获得自己的 rank ID。
- 通过 IP Socket 交换 NCCL unique ID 和连接信息。
- NCCL 探测 GPU、PCIe、HCA 和节点拓扑。
- 构造 ring/tree/channel。
- 选择真正的数据传输后端:P2P、SHM、NET/IB 或 NET/Socket。
NCCL_SOCKET_IFNAME 不保证“只用于 bootstrap”。
RDMA 正常时它主要承担 bootstrap;RDMA 失败并回退 Socket 后,它也会决定大块 Tensor
数据走哪张 IP 网卡。
5. 常见 NCCL 参数
NCCL_SOCKET_IFNAME
筛选 NCCL 可使用的 Linux IP 接口。精确指定接口时可写:
NCCL_SOCKET_IFNAME="=eth0"
- RDMA 正常:主要影响 bootstrap/OOB IP 连接。
- RDMA 不可用:决定
NET/Socket的数据网卡。 - 部署时只允许使用计算网
eth0/eth3;Socket 回退时不能落到其他接口。
NCCL_IB_HCA
筛选 NCCL 的 RDMA HCA。推荐使用精确匹配:
NCCL_IB_HCA="=mlx5_0:1,mlx5_3:1"
这个变量只是“允许选择谁”,不会自动把宿主机 RDMA 设备送进容器。
容器还必须看到 /dev/infiniband/rdma_cm、
uverbs0 和 uverbs3。
NCCL_CROSS_NIC
| 值 | 行为 | 适用直觉 |
|---|---|---|
0 |
尽量让同一 ring/tree 在不同节点使用对应的同一条 Rail。 | 每张 NIC 接不同交换机、跨 Rail 代价高的 rail-optimized 网络。 |
1 |
允许同一 ring/tree 在不同节点使用不同 NIC。 | 所有 NIC 进入同一网络 Fabric,跨 NIC 不构成额外问题。 |
2 |
优先对应同一 NIC,但必要时允许跨 NIC。 | NCCL 默认的折中策略。 |
mlx5_0 和 mlx5_3 分挂 switch 1/2,
拓扑直觉上更偏向 0 或默认 2。最终值必须在
真正启用 NET/IB 后用 all_reduce 和 SGLang 端到端 A/B 决定。
当 NCCL 使用 NET/Socket 时,这个参数不参与路径选择。
NCCL_DEBUG 与 NCCL_DEBUG_SUBSYS
NCCL_DEBUG=INFO
NCCL_DEBUG_SUBSYS=INIT,NET,GRAPH,TUNING
用于确认实际路径,诊断完成后应关闭,正式性能数据不要长期带 INFO 日志。
6. NCCL 日志速查
| 日志 | 含义 | 判断 |
|---|---|---|
Bootstrap: Using eth0:... |
初始化控制连接选择 eth0。 | 只说明 bootstrap,尚不能证明数据走 RDMA。 |
NET/IB : Using ... mlx5_0 ... |
NCCL 已识别 RDMA HCA。 | RDMA 数据后端可用。 |
via NET/IB/.../GDRDMA |
跨机边通过 GPUDirect RDMA。 | 理想证据。 |
NET/IB : No device found |
容器没有可用 RDMA 设备或驱动/权限不完整。 | 继续看是否回退 Socket。 |
NET/Socket : Using 非计算网... |
跨机数据由普通 TCP Socket 传输。 | 若误入低速非计算网,性能会严重受限。 |
via P2P/IPC |
同机 GPU 通过 CUDA P2P/IPC。 | 机内路径,不代表跨机路径。 |
7. 2026-07-30 Prefill 变慢事故复盘
已观测事实
- 宿主机存在
/dev/infiniband,两条 400G Rail 均 Up。 - 原脚本容器内不存在
/dev/infiniband。 - NCCL INFO 明确打印
NET/IB : No device found和Using network Socket。 - 原脚本选择 400G 计算网
eth0;quick-map 曾误选低速非计算网。 - 部署规定只有
eth0/eth3用于节点间通信,两者均为 400G。
| 冷缓存 Shape | 原脚本网络:eth0 Socket | quick-map:错误的非计算网 | 差异 |
|---|---|---|---|
| 1K → 1, C=1 | TTFT 1.458s / 693.1 input tok/s | TTFT 15.88–16.04s / 约 64 tok/s | 约 10.9× |
| 32K → 1, C=1 | TTFT 38.062s / 860.5 input tok/s | TTFT 504.44s / 64.96 tok/s | 约 13.25× |
NCCL_SOCKET_IFNAME
设成低速非计算网。NCCL 回退 NET/Socket 后,TP16 跨机数据没有进入规定的
eth0/eth3 计算网。NCCL_CROSS_NIC=1 在没有 NET/IB
的情况下不是致因。
为什么旧日志还会比 38 秒更短
旧矩阵脚本还有第二个独立因素:warmup_requests=16、固定
seed=42、ISL/OSL/C 升序运行,而且从不 flush Prefix Cache。
因此旧日志混入缓存命中,不能直接与冷 Prefill 比较。
eth0/eth3 和
mlx5_0/mlx5_3,并会透传精确 RDMA 设备、强制检查两端
NET/IB 日志。代码与 dry-run 已通过;下一步是真机启动验证,
在拿到运行时证据前不进入 Kernel 归因。
8. 从宿主机到 NCCL 的排查清单
-
宿主机链路:
ethtool eth0、ethtool eth3。 -
HCA 映射:
ibdev2netdev,确认mlx5_0→eth0、mlx5_3→eth3。 -
宿主机设备:
ls -l /dev/infiniband。 -
容器设备:
docker exec CONTAINER ls -l /dev/infiniband。 宿主机有、容器没有,NCCL 仍然用不了 RDMA。 -
运行时证据:
用一次
NCCL_DEBUG=INFO启动,搜索NET/IB、NET/Socket、GDRDMA。 - 硬件计数器: 同时观察 eth0/eth3 流量和 RDMA 端口计数;不能只看环境变量。
- 端到端 A/B: 冷缓存、同一 prompt、同一模型参数,仅改变一个网络变量。
最小 RDMA 设备透传验证
docker run --rm \
--device=/dev/infiniband/rdma_cm \
--device=/dev/infiniband/uverbs0 \
--device=/dev/infiniband/uverbs3 \
IMAGE \
ls -l /dev/infiniband
能看到设备只是第一关。最终仍必须从 NCCL INFO 中看到 NET/IB,
并通过通信基准与 SGLang 结果确认。