分布式训练网络全面解析:从 TCP/IP 到 NCCL
分布式训练网络全面解析:从 TCP/IP 到 NCCL
本文系统梳理分布式 AI 训练中涉及的网络知识,涵盖 TCP/IP 基础、RDMA 原理、InfiniBand、RoCE 无损网络、GPU 互联硬件、NCCL 核心原理、集合通信操作及故障排查调优,适合深度学习基础设施工程师和 MLSys 研究者参考。
目录
一、TCP/IP 基础网络
1.1 TCP 和 UDP 的区别?NCCL 什么场景下用 TCP?
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠(ACK、重传) | 不可靠 |
| 顺序 | 保证顺序 | 不保证 |
| 流控 | 有拥塞控制 | 无 |
| 开销 | 高(头部 20B+) | 低(头部 8B) |
| 延迟 | 高 | 低 |
NCCL 使用 TCP 的场景:
- Bootstrap 阶段:NCCL 初始化时,所有 rank 通过 TCP socket 交换元信息(IP、端口、能力协商)
- 没有 RDMA 网卡时的 fallback:若
NCCL_IB_DISABLE=1或无 IB/RoCE 网卡,NCCL 退化为 TCP socket 传输 - 跨数据中心低带宽链路:有时 TCP+压缩比 RDMA 更合适

1.2 TCP 三次握手和四次挥手

为什么挥手是四次?
握手时 SYN+ACK 可以合并,因为服务端在收到 SYN 时立刻准备好了。挥手不能合并:收到客户端 FIN 后,服务端可能还有数据要发,必须先单独回 ACK,等数据发完再发自己的 FIN。所以 ACK 和 FIN 分两次发送,共四次。
1.3 TCP 拥塞控制的四个阶段

| 阶段 | 触发条件 | cwnd 行为 |
|---|---|---|
| 慢启动 | 初始或超时后 | 每个 RTT 翻倍 |
| 拥塞避免 | cwnd ≥ ssthresh | 每个 RTT +1 MSS |
| 快速重传 | 收到 3 个重复 ACK | 立即重传,不等超时 |
| 快速恢复 | 快速重传后 | ssthresh=cwnd/2,cwnd=ssthresh+3 |
1.4 TCP 为什么不适合 RDMA 场景?

TCP 的核心问题:
- 高 CPU 开销:协议栈处理(校验和、分片、拥塞控制)消耗大量 CPU cycle
- 多次内存拷贝:GPU→CPU buffer→内核 socket buffer→网卡,延迟叠加
- 系统调用开销:每次 send/recv 都需要用户态↔内核态切换
- 高延迟:典型 TCP 延迟 10~100μs,RDMA 可达 1~2μs
- 带宽浪费:NCCL AllReduce 需要极高吞吐,TCP 拥塞控制保守
1.5 Socket 通信与 NCCL_SOCKET_IFNAME
Socket 通信是操作系统提供的网络 API,应用程序通过 socket()→bind()→listen()→accept()/connect()→send()/recv() 进行通信。
NCCL_SOCKET_IFNAME 指定 NCCL Bootstrap TCP 通信使用的网络接口:
1 | # 指定使用 eth0 接口 |
重要:多网卡机器上,NCCL 可能选错接口(如选了 lo 或 docker0),导致 rank 间无法通信或性能极差。
二、RDMA 原理
2.1 RDMA 三个核心优势

RDMA(Remote Direct Memory Access,远程直接内存访问)之所以能在 AI 训练中取代 TCP,核心在于三点:
-
Kernel Bypass(内核旁路):传统 TCP 每次收发都要经过操作系统内核的协议栈,涉及系统调用、上下文切换和数据校验。RDMA 将协议栈卸载到网卡硬件(RNIC),应用程序直接在用户态与网卡交互,完全绕过内核,延迟从 10~100μs 降至 1~2μs。
-
Zero Copy(零拷贝):TCP 数据路径为 GPU 显存 → CPU buffer → 内核 socket buffer → 网卡,至少经历 2~3 次内存拷贝。RDMA 通过 GPUDirect 技术,让网卡 DMA 引擎直接读写 GPU 显存,数据路径中没有任何 CPU 介入的拷贝操作,大幅降低延迟并释放 CPU。
-
CPU Offload(CPU 卸载):RDMA 的 Write/Read 操作是"单边操作"——发起方可以在对端 CPU 毫不知情的情况下直接读写其内存,整个传输过程不消耗对端 CPU cycle。这对 GPU 训练意义重大:CPU 可以专注于调度和预处理,不再成为通信瓶颈。
2.2 RDMA 三种实现方式

| InfiniBand | RoCEv2 | iWARP | |
|---|---|---|---|
| 传输层 | IB 协议 | UDP/IP | TCP/IP |
| 可路由 | 是(GRH) | 是 | 是 |
| 无损要求 | IB 自带 FC | 需要 PFC+ECN | 不需要 |
| 延迟 | ~1μs | ~2μs | ~5μs |
| 成本 | 最高 | 中 | 低 |
| AI 训练主流 | ✓✓✓ | ✓✓ | 少用 |
三种方案的本质区别在于"RDMA 语义跑在什么传输层之上":
InfiniBand(IB) 是最纯粹的方案——它是一套从物理层到传输层完全独立于以太网的专有协议栈。IB 从设计之初就以 RDMA 为核心目标,流控(Credit-Based Flow Control)是内建的,网络天然无损,不需要 PFC 这类外部补丁。代价是需要专用的 HCA 网卡、IB 交换机和 Subnet Manager,生态封闭,造价高。
RoCEv2 是"把 RDMA 搬到以太网上"的方案。将 InfiniBand 传输层(IB Transport)封装在 UDP/IP 报文中,复用现有的以太网交换机和网卡(需要支持 RoCEv2 的 RDMA 网卡,如 Mellanox ConnectX 系列)。可路由、成本低,但由于以太网本身不提供无损保证,必须通过 PFC + ECN(DCQCN)在交换机层面模拟出无损环境。这是目前大规模 AI 训练集群的主流选择之一。
iWARP 将 RDMA 协议跑在 TCP/IP 之上。TCP 本身有重传和流控,理论上不需要无损网络,但代价是协议栈复杂,延迟高(~5μs),且 TCP 的拥塞控制和 RDMA 的高吞吐需求存在根本矛盾。实际上 iWARP 在 AI 训练中几乎不用,主要出现在存储(NVMe-oF)领域。
2.3 QP(Queue Pair)— RDMA 通信基本单元

QP 是 RDMA 通信的核心抽象,可以类比 TCP 中的 socket 连接。每个 QP 由一对队列组成:
- SQ(Send Queue,发送队列):应用程序将 Work Request(WR,工作请求)投递到 SQ,告诉网卡"发送这段内存的数据"或"写到对端这个地址"
- RQ(Receive Queue,接收队列):应用程序提前投递 Receive Request,告诉网卡"数据来了放到这里"
网卡(RNIC)以硬件轮询的方式消费这两个队列,完全绕过 CPU。操作完成后,网卡将结果写入 CQ(Completion Queue,完成队列),应用程序通过轮询 CQ 或注册回调来感知完成事件。
整个过程中,应用程序只做"投递请求"和"检查完成"两个动作,真正的传输、分片、确认全部由硬件完成。这就是 RDMA 实现 CPU Offload 的核心机制。
QP 类型:
| 类型 | 全称 | 特点 |
|---|---|---|
| RC | Reliable Connected | 点对点可靠连接,NCCL 主要使用 |
| UC | Unreliable Connected | 连接但不可靠 |
| UD | Unreliable Datagram | 类似 UDP,一对多 |
| RD | Reliable Datagram | 可靠多播(IB 专有) |
NCCL 主要使用 RC QP,因为 AllReduce 等操作要求数据完整到达,RC 提供按序、可靠的点对点语义,且支持 RDMA Write 单边操作。在 N 个 GPU 的集群中,每对需要直接通信的 rank 之间都会建立一个 RC QP,因此 QP 数量随规模平方增长,这也是超大规模集群(千卡以上)初始化慢的原因之一。
2.4 Send/Recv vs Write/Read

| Send/Recv | Write | Read | |
|---|---|---|---|
| 操作类型 | 双边 | 单边 | 单边 |
| 接收方 CPU | 需要参与 | 不需要 | 不需要 |
| 适用场景 | 控制消息 | 大数据传输(NCCL首选) | 远程读取 |
| 性能 | 较低 | 最高 | 高 |
双边操作(Send/Recv):
Send 和 Recv 必须配对出现。发送方调用 ibv_post_send,接收方必须提前调用 ibv_post_recv 投递接收缓冲区,两端 CPU 都要参与。这与普通 TCP socket 的使用方式类似,好处是接收方可以灵活决定"把数据放在哪里",坏处是接收方 CPU 必须随时在线处理 Recv 请求,无法完全卸载。
单边操作(Write/Read):
- RDMA Write:发送方直接将本地内存写入对端指定地址(需持有对端的 rkey 和虚拟地址),对端 CPU 完全不感知,无需任何配合。这是 NCCL 节点间大数据传输的首选方式。
- RDMA Read:发送方主动从对端拉取数据,同样无需对端 CPU 参与。但每个 Read 都会占用一个 RDMA Read 资源(硬件限制每个 QP 的并发 Read 数),吞吐不如 Write,多用于存储类场景(如 NVMe-oF)。
NCCL 为什么首选 Write?
在 AllReduce 的 Ring 算法中,每个 GPU 需要将数据"推"给下一个 GPU——这完美匹配 RDMA Write 的语义:发送方主动写,接收方只需提前注册好内存(MR),无需 CPU 介入。相比之下,Send/Recv 要求接收方不断投递 RQ,在 NCCL 的高频通信下会带来额外的 CPU 开销,破坏 CPU Offload 的优势。
2.5 MR(Memory Region)— 为什么需要注册内存?

必须注册的原因:
- 内存 Pin(锁页):防止操作系统将内存 swap 到磁盘,网卡 DMA 需要稳定的物理地址
- 安全保护:rkey 是访问令牌,防止未授权的远程内存访问
- 地址转换:网卡需要知道虚拟地址对应的物理地址(通过 MMU/IOMMU)
注意:注册/注销 MR 开销较大(μs 级),NCCL 会在初始化时批量注册,运行时复用。
三、InfiniBand 网络
3.1 IB 网络层次结构

关键组件:
- HCA(Host Channel Adapter):主机侧 RDMA 网卡(类比 NIC)
- IB Switch:交换机,支持 Cut-Through 转发,延迟 ~100ns
- Subnet Manager(SM):管理整个 IB 子网,分配 LID,计算路由,类似 SDN 控制器
3.2 LID 和 GID
| LID | GID | |
|---|---|---|
| 全称 | Local Identifier | Global Identifier |
| 范围 | 子网内唯一 | 全局唯一 |
| 长度 | 16 bit | 128 bit(类似 IPv6) |
| 用途 | 子网内路由 | 跨子网路由(RoCEv2 也用) |
| 分配 | Subnet Manager 分配 | 基于 GUID 派生 |
LID(Local Identifier) 是 IB 子网内的路由地址,16 bit 意味着一个 IB 子网最多有 65535 个端口地址。IB 交换机根据报文头中的目标 LID 查表转发,路由表由 Subnet Manager(SM)计算并下发,类似 SDN 控制器集中管控。SM 负责整个子网的拓扑发现、LID 分配和路由计算,是 IB 网络的"大脑"——如果 SM 故障,新设备无法加入,已建立的连接仍然工作,但网络变更无法响应。
GID(Global Identifier) 是全局唯一地址,128 bit,格式类似 IPv6。每个 IB 端口有一个全局唯一的 GUID(出厂烧录),GID 基于 GUID 派生。GID 用于跨子网路由(通过 GRH 报文头携带),以及 RoCEv2 的地址标识——RoCEv2 直接复用 GID 作为 IP 层地址(即 IPv6 地址),这是 RoCEv2 能跨子网路由的技术基础。
1 | GID 格式示例: |
在 NCCL 中的意义: RoCEv2 环境下,NCCL_IB_GID_INDEX 参数控制使用哪个 GID 条目(每个端口可能有多个 GID,对应不同的 IP 配置)。选错 GID 会导致 NCCL 建立 QP 时使用错误的地址,rank 间无法通信。
1 | # 查看网卡的 GID 表 |
3.3 IB 交换机的 Fat-Tree 拓扑

优点:
- 全等分带宽(Full Bisection Bandwidth):任意两点间带宽相等
- 多路径:Core 层存在多条等价路径,支持 ECMP
- 易扩展:K-ary Fat-Tree 可扩展到 k³/4 台主机
缺点:
- 成本高:需要大量交换机和线缆(k-ary 需要 5k²/4 个交换机)
- 线缆复杂:布线管理困难
- 超额订购:实际部署常用 2:1 或 4:1 超额订购降低成本
3.4 SHARP(In-Network Computing)

SHARP 对 NCCL 的意义:
- AllReduce 延迟从 O(log N) 降至 O(1)(交换机完成聚合)
- 节省主机网络带宽(减少流量 ~50%)
- NCCL 通过
NCCL_ALGO=CollNet启用 SHARP - 需要 MLNX SHARP daemon 和支持 SHARP 的 IB 交换机(Spectrum/Quantum)
四、RoCE 与无损以太网
4.1 RoCEv1 vs RoCEv2
| RoCEv1 | RoCEv2 | |
|---|---|---|
| 封装 | Ethernet(L2) | UDP/IP(L3) |
| 可路由 | 否(同子网) | 是(跨子网) |
| 目标端口 | 不适用 | UDP 4791 |
| PFC 支持 | 必须 | 必须 |
| 生产使用 | 很少 | 主流 |
RoCEv1 的局限性: v1 直接在以太网帧上封装 IB 传输层,没有 IP 层。这意味着它只能在同一个二层广播域(L2 子网)内工作,无法被 IP 路由器转发。一旦训练集群规模超过单个交换机子网,v1 就无能为力。此外,v1 的 PFC 配置在大型网络中管理复杂,实际上几乎没有大规模生产部署。
RoCEv2 的改进: v2 在 IB 传输层外面套了一层 UDP/IP 报头(UDP 目标端口固定为 4791 作为协议标识)。加了 IP 层之后:
- 可路由:标准 IP 路由器可以转发 RoCEv2 报文,训练集群可以跨多个交换机子网部署,规模不再受 L2 限制
- 使用 GID 寻址:v2 用 GID(本质是 IPv6 地址)标识端点,与 IP 协议栈统一
- ECMP 支持:多条等价路径之间可以基于 UDP 五元组做负载均衡,提升带宽利用率
v2 仍然需要无损网络(PFC + ECN),这一点与 v1 相同。目前几乎所有大规模 AI 训练集群的以太网 RDMA 方案都使用 RoCEv2。
4.2 RoCE 为什么必须运行在无损网络?

核心原因:RDMA RC QP 虽然可以重传,但重传逻辑复杂,且网卡超时重传会导致 QP 状态机出错,实际上一旦出现丢包,NCCL 通信会 hang 住或报错。RDMA 的设计假设底层网络基本无损。
更本质地理解这一点:以太网的丢包处理是"上层协议(TCP)负责重传",但 RDMA 协议栈在网卡里,一旦发送方网卡发出的报文在网络中被丢弃:
- RC QP 重传超时:发送方等待 ACK 超时后触发重传,但在此期间整条 QP 被阻塞,没有任何新数据可以发送
- QP 状态机异常:多次重传失败后,QP 进入 Error 状态,必须重建连接,NCCL 无法自动恢复,训练进程会卡死
- 慢路径代价极高:重传一次报文的代价是 μs 级延迟变成 ms 级,在高并发 AllReduce 中会导致整个 barrier 等待
这就是为什么 RoCE 环境必须配置 PFC + ECN(DCQCN) 来保证网络无损——不是为了锦上添花,而是 RDMA 正确运行的前提条件。
4.3 PFC(Priority Flow Control)

PFC 是以太网的"局部刹车"机制,工作在 IEEE 802.1Qbb 标准中。传统以太网没有流控,交换机缓冲区满了就直接丢包。PFC 在此基础上引入了逐跳、逐优先级的反压:
- 以太网帧支持 8 个优先级(CoS 0~7),RDMA 流量通常走优先级 3 或 4
- 当交换机入口缓冲区的某个优先级队列超过阈值时,向上游发送 PAUSE 帧,要求上游暂停发该优先级的数据
- 上游收到 PAUSE 后,在指定时间内停发该优先级的帧,等 PAUSE 到期或收到 UNPAUSE 后继续
这样丢包就被替换成了"暂停",报文得以保全,RDMA 的无损传输假设得以成立。
PFC 副作用 — 死锁(Deadlock):

其他副作用:
- Head-of-Line Blocking:同优先级的无辜流量被一起暂停
- PAUSE 帧传播:一个拥塞点的 PAUSE 可以级联传播到全网
- Buffer bloat:过大的 PAUSE 时间导致延迟抖动
解决方案:配合 ECN 使用(DCQCN),在 PAUSE 发生前就降速。
4.4 ECN 与 PFC 如何配合

ECN(Explicit Congestion Notification,显式拥塞通知) 是交换机向发送方"打信号"的主动拥塞控制机制:
- 交换机配置一个队列长度阈值(如缓冲区的 30%)
- 当入口队列超过阈值时,交换机在转发的报文头中打上 ECN 标记(CE 位置 1),报文不丢弃,继续转发
- 接收方收到带 ECN 标记的报文后,在 ACK 报文中回复 CNP(Congestion Notification Packet)给发送方
- 发送方收到 CNP 后,按 DCQCN 算法降低发送速率
与 PFC 相比,ECN 的关键优势是端到端的信号——它直接告诉发送方"你发太快了,降速",而 PFC 只是逐跳暂停,不解决根本的速率匹配问题。
ECN vs PFC 分工:
| 机制 | 角色 | 触发时机 |
|---|---|---|
| ECN | 主动预防,早期降速 | 队列超过阈值(软控制) |
| PFC | 被动保障,最后防线 | 缓冲区将满(硬刹车) |
两者阈值需要合理配置:ECN 阈值必须低于 PFC 阈值,否则 ECN 还没来得及让发送方降速,PFC 就已经触发了,ECN 形同虚设。理想情况下,ECN 持续有效地管理速率,队列长度保持在低水位,PFC 很少甚至从不触发。
4.5 DCQCN
DCQCN(Data Center Quantized Congestion Notification)是 Microsoft 和 Mellanox 联合提出的 RoCEv2 拥塞控制算法,结合 ECN + PFC:

三个关键参数:
α:EWMA 拥塞估计,控制降速幅度Byte Counter:无拥塞时每发 X 字节就增加速率Timer:每隔 T 时间也增加速率(防止长时间不发包时无法恢复)
五、GPU 互联硬件
5.1 NVLink vs PCIe

| NVLink 4.0 | PCIe 5.0 x16 | |
|---|---|---|
| 带宽(单向) | 450 GB/s | 32 GB/s |
| 带宽(双向) | 900 GB/s | 64 GB/s |
| 延迟 | ~1μs | ~2-3μs |
| 连接方式 | GPU 直连 | 通过 CPU/Switch |
| 适用场景 | 同节点 GPU 间 | GPU-CPU、跨节点 |
| H100 配置 | 8 GPU 全互联 | 额外用于 NIC 连接 |
为什么 NVLink 带宽远超 PCIe?
PCIe 是一条"公共总线",连接 CPU、GPU、NIC、SSD 等各种外设,带宽要在所有设备之间共享,且必须经过 CPU 的 PCIe Root Complex 中转。PCIe 5.0 x16 的 64 GB/s 双向带宽已经是当前 PCIe 的天花板,但受制于通用性和引脚数量,无法无限扩展。
NVLink 是 NVIDIA 专为 GPU-GPU 直连设计的点对点互联协议,每条 NVLink 4.0 link 有 25 GB/s 带宽,H100 每个 GPU 有 18 条 NVLink,合计 900 GB/s 双向带宽,是 PCIe 的 14 倍。更重要的是,NVLink 绕过了 CPU,两个 GPU 之间直接通信,延迟更低,CPU 不会成为瓶颈。
在没有 NVLink 的时代(早期 Tesla/Pascal),多 GPU 训练只能通过 PCIe 通信,GPU 间数据传输必须经由 CPU 内存中转(GPU→CPU Memory→GPU),带宽受限且 CPU 占用高。NVLink 的出现彻底改变了单机多 GPU 通信的性能上限。
5.2 NVSwitch 的作用

没有 NVSwitch 时的问题:
NVLink 是点对点连接,每条 link 只能连接两个 GPU。如果 8 个 GPU 要实现两两直连(全互联),需要 8×7/2 = 28 条 NVLink。H100 每个 GPU 只有 18 条 NVLink,这根本不够全互联,而且随着 GPU 数量增加,所需 link 数以平方增长,直连方案根本无法扩展。
NVSwitch 的解决方案:
NVSwitch 是一个 NVLink 交换芯片,类比以太网交换机——所有 GPU 不再两两直连,而是连到 NVSwitch。在 DGX H100 中:
- 8 个 GPU,4 个 NVSwitch
- 每个 GPU 与每个 NVSwitch 之间有 2 条 NVLink,合计每个 GPU 使用 8 条 NVLink 连接到 4 个 NVSwitch
- 任意两个 GPU 之间,数据通过某个 NVSwitch 中转,全程不经过 CPU
- 由于每个 GPU 与每个 NVSwitch 有 2 条 NVLink(50 GB/s 单向),4 个 NVSwitch 提供的总带宽为 4×2×25 = 200 GB/s 单向(即 400 GB/s 双向,实际标称 900 GB/s 双向是所有 NVLink 加总)
效果:
- 任意两个 GPU 间都有充足的带宽,单个 GPU 对的带宽不随 GPU 总数下降(非共享瓶颈)
- NCCL 的节点内 AllReduce 可以在 NVSwitch 构成的全互联拓扑上运行,不需要 Ring 那样的多跳传输
NVSwitch 3.0 还新增了 in-network reduction 能力(类似 InfiniBand 的 SHARP),AllReduce 可以在 NVSwitch 芯片上直接完成 reduce 计算,进一步降低延迟。
- DGX H100:4 个 NVSwitch,每个 GPU 与每个 NVSwitch 都有 2 条 NVLink
- 效果:任意两个 GPU 间都有 900 GB/s 全双工带宽(非共享)
- NVSwitch 3.0:支持 SHARP-like 的 in-network reduction(MultiNode AllReduce 加速)
5.3 nvidia-smi topo -m 输出解释
1 | GPU0 GPU1 GPU2 GPU3 NIC0 CPU Affinity |
| 标识 | 全称 | 含义 |
|---|---|---|
| NVX | NVLink X条 | 通过 X 条 NVLink 直连 |
| PIX | PCIe Internal crossing | 同一 PCIe Switch 下,不跨 CPU |
| PXB | PCIe crossing Bridge | 跨 PCIe Switch,但同一 NUMA |
| PHB | PCIe Host Bridge | 经过 PCIe Host Bridge(CPU PCIe 控制器) |
| NODE | NUMA Node | 同一 NUMA 节点,但通过 QPI/UPI 互联 |
| SYS | System | 跨 NUMA 节点,最远路径 |
性能排序(由快到慢):NVLink > PIX > PXB > PHB > NODE > SYS
5.4 GPU Direct RDMA(GDR)

原理:通过 nvidia-peermem(或 nv_peer_mem)内核模块,让 RDMA 网卡可以直接访问 GPU 的 BAR(Base Address Register)空间,网卡 DMA 直接读写 GPU 显存。
限制:
- 拓扑限制:GPU 和 RDMA 网卡必须在同一 PCIe Root Complex 下
- BAR 大小限制:老 GPU 的 BAR1 只有 256MB(H100 已解决此问题)
- 驱动要求:需要
nvidia-peermem正确加载 - 不支持 CUDA 统一内存:UVM 页面不能用于 GDR
1 | # 检查 GDR 是否工作 |
六、NCCL 核心原理
6.1 NCCL 的两套网络

| 网络 | 作用 | 传输方式 | 相关环境变量 |
|---|---|---|---|
| 节点内 P2P | GPU 间直接访问 | NVLink、PCIe P2P、共享内存 | NCCL_P2P_DISABLE, NCCL_SHM_DISABLE |
| 节点间网络 | 跨机器通信 | RDMA (IB/RoCE)、TCP | NCCL_IB_DISABLE, NCCL_NET |
6.2 NCCL 初始化流程

NCCL 初始化是训练作业启动后最先发生的耗时操作,完整流程分为以下几步:
Step 1 — Bootstrap(TCP 握手)
所有 rank 通过 NCCL_SOCKET_IFNAME 指定的 TCP 接口互相连接,交换各自的 IP、端口、GPU 信息。这一步是 NCCL 唯一强依赖 TCP 的阶段,rank 0 通常作为 rendezvous 点(或使用外部 store 如 etcd/Redis)。
Step 2 — 拓扑探测
每个进程调用 nvidia-smi、读取 /sys/bus/pci 等系统信息,探测本机的 GPU-NIC 拓扑(NVLink 连接数、PCIe 亲和性、NUMA 归属)。这是 NCCL 后续选择最优通信路径的依据。
Step 3 — 通信图构建
NCCL 根据全局拓扑信息,构建 Ring 或 Tree 的逻辑通信图,决定每个 rank 的前驱/后继关系。大规模集群中,NCCL 会同时构建多条 Ring(NCCL_NCHANNELS 控制数量)以充分利用多网卡带宽。
Step 4 — QP 建立(RDMA 路径)
若使用 InfiniBand 或 RoCE,NCCL 会在需要直连通信的 rank 对之间建立 RC QP,交换 LID/GID、rkey 等信息,并注册通信缓冲区(ibv_reg_mr)。
Step 5 — Channel 初始化
分配 CUDA stream、共享内存 buffer、FIFO 队列等资源,NCCL channel 就绪后,后续的集合通信操作才能提交到这些 channel 上执行。
常见坑:初始化阶段若 rank 间 TCP 不通(防火墙、错误的 IFNAME)会卡在 Step 1;若 IB QP 建立失败(权限、MTU 不匹配)会卡在 Step 4,日志中通常看到
NCCL INFO停止更新。
6.3 NCCL 如何选择 Ring 还是 Tree 算法?

决策公式(简化):
- Ring 延迟 ≈
2(N-1)/N × (α + M/B)→ 大消息占优 - Tree 延迟 ≈
2log₂(N) × (α + M/B)→ 节点多时占优
其中 α 是延迟(latency),M 是消息大小,B 是带宽,N 是 rank 数。
直觉解释:
-
Ring 的步数是
2(N-1),每步传输M/N的数据。N 很大时,步数虽然多,但每步数据量小,管道化后整体带宽利用率接近 100%。适合大消息、带宽敏感场景(如 AllReduce 梯度,动辄 GB 级)。 -
Tree(Double Binary Tree) 的步数是
2·log₂N,对数级增长。1024 个 GPU 时 Ring 需要 2046 步而 Tree 只需约 20 步,延迟占优。但每个节点同时要做发送和接收,带宽利用率只有约 50%。适合小消息、延迟敏感场景(如 AllReduce 标量损失值)。
NCCL 在运行时会根据消息大小自动切换:小消息走 LL/Tree,大消息走 Ring/Simple。可以通过 NCCL_ALGO 和 NCCL_PROTO 环境变量强制指定,但通常不建议,除非在 profiling 后有明确数据支撑。
6.4 Ring AllReduce 完整步骤和通信量

Phase 1: Scatter-Reduce(N-1 步)
每一步,每个 GPU 将自己的一个 chunk 发给下一个 GPU,同时接收上一个 GPU 的 chunk 并与本地对应 chunk 累加:
1 | Step 1: GPU0→GPU1(a0), GPU1→GPU2(b1), GPU2→GPU3(c2), GPU3→GPU0(d3) |
Phase 2: AllGather(N-1 步)
将 Scatter-Reduce 得到的完整 chunk 广播到所有 GPU。
通信量公式:
1 | 每个 GPU 发送量 = 2 × (N-1)/N × M |
其中 M 是总数据量,N 是 GPU 数。
6.5 Double Binary Tree 算法

工作原理:
- 构建两棵互补的二叉树(叶子节点互换)
- Reduce 阶段:两棵树同时自底向上 Reduce
- Broadcast 阶段:两棵树同时自顶向下 Broadcast
- 每个节点在一棵树中是内部节点,在另一棵树中是叶子节点
优势 vs 代价:
| Double Binary Tree | Ring | |
|---|---|---|
| 延迟 | O(2·log₂N) | O(N) |
| 带宽利用率 | ~50% | ~100% |
| 适用场景 | 小消息,延迟敏感 | 大消息,带宽敏感 |
| N=1024 步数 | 20 步 | 1023 步 |
6.6 NCCL 三种传输协议
| 协议 | 全称 | 特点 | 适用场景 |
|---|---|---|---|
| Simple | Simple | 标准 RDMA Write,大 chunk | 大消息,高带宽 |
| LL | Low Latency | 64B flag+data 内联,轮询检测 | 小消息,延迟敏感 |
| LL128 | Low Latency 128 | 120B data + 8B flag,NVLink 优化 | NVLink 节点内小消息 |
1 | LL 协议数据格式: |
6.7 algbw 和 busbw
1 | algbw(算法带宽):从用户角度看的端到端带宽 |
各操作的通信系数:
| 操作 | 通信系数 | 公式 |
|---|---|---|
| AllReduce | 2(N-1)/N |
≈ 2(N大时) |
| AllGather | (N-1)/N |
≈ 1 |
| ReduceScatter | (N-1)/N |
≈ 1 |
| Broadcast | (N-1)/N |
≈ 1 |
| AllToAll | (N-1)/N |
≈ 1 |
1 | # nccl-tests 输出示例 |
七、集合通信操作应用
7.1 数据并行(DDP)中 AllReduce 的通信量

在数据并行(DDP)中,每个 GPU 持有一份完整的模型副本,处理不同的数据分片。反向传播结束后,所有 GPU 需要将各自的梯度求和取平均,这正是 AllReduce 操作的用途。
通信发生的时机:
- PyTorch DDP 默认在反向传播过程中边计算边通信(bucket-based overlap),将梯度分桶,每桶满了就触发 AllReduce,与后续层的反向计算重叠
- 通信结束后,每个 GPU 持有完全一致的平均梯度,各自更新本地参数
公式:
- 每个 GPU 发送/接收 =
2 × (N-1)/N × Φ≈2Φ - GPT-3 175B FP16:Φ = 350GB,每次迭代通信 ~700GB(所有机器总计)
这里系数 2 来自 Ring AllReduce 的两个阶段(Scatter-Reduce + AllGather),每个阶段每个 GPU 各传输约 (N-1)/N × Φ 的数据。当 N 足够大时,系数趋近于 2。这意味着模型越大、GPU 越多,每次迭代的通信量也越大,这是大模型训练必须使用高带宽网络(IB/NVLink)的根本原因。
7.2 ZeRO 三个阶段

ZeRO(Zero Redundancy Optimizer)是 DeepSpeed 提出的内存优化策略,核心思想是:既然 DDP 中每个 GPU 都持有一份完全相同的副本(参数、梯度、优化器状态),那这份冗余完全可以被消除——只要在需要时通过通信重建即可。
三个阶段的递进逻辑:
- Stage 1:优化器状态(Adam 的 m/v 矩、FP32 主参数)占显存的大头(约 12 bytes/param for fp16 训练),将其分片到各 GPU。梯度仍然 AllReduce,但每个 GPU 只更新自己分片对应的参数,最后一步 AllGather 同步参数。
- Stage 2:在 Stage 1 基础上,梯度也分片。反向传播时改为 ReduceScatter(每个 GPU 只接收自己需要的梯度分片),节省梯度显存。通信量与 DDP 相同,但显存减半。
- Stage 3:参数本身也分片。前向和后向都需要先 AllGather 拿到完整参数,后向结束后再 ReduceScatter 梯度。通信量增加到约
3Φ,但显存随 GPU 数量线性降低,是训练万亿参数模型的关键手段。
| ZeRO 阶段 | 分片内容 | 通信操作 | 通信量 | 显存节省 |
|---|---|---|---|---|
| Stage 1 | 优化器状态 | AllReduce 梯度 | 2Φ |
~4x |
| Stage 2 | 优化器状态 + 梯度 | ReduceScatter + AllGather | 2Φ |
~8x |
| Stage 3 | 全部参数 | 前向 AllGather + 后向 ReduceScatter×2 | 3Φ |
~N倍 |
7.3 Tensor Parallel 中的 AllReduce
以 Megatron-LM 的列/行并行为例:

AllReduce 发生位置:
- 前向传播:行并行线性层后做 AllReduce(合并各 GPU 的部分和)
- 后向传播:列并行线性层的梯度做 AllReduce
通信量(每个 Transformer 层):
1 | 每次 AllReduce 数据量 = batch_size × seq_len × hidden_size × 2字节(FP16) |
7.4 Pipeline Parallel 通信操作

为什么通信量小?
PP 只在相邻 Stage 间传递激活值(activation),通信量远小于 TP 的 AllReduce:
1 | PP 通信量 = micro_batch_size × seq_len × hidden_size × 2Bytes |
但 PP 有 bubble time(流水线气泡) 问题,需要用 1F1B 调度或 Interleaved PP 来缓解。
八、故障排查与调优
8.1 NCCL 常用调试环境变量
1 | # === 日志级别 === |
8.2 训练 Hang 死排查

常见 Hang 原因和解决方案:
| 原因 | 诊断命令 | 解决方案 |
|---|---|---|
| rank 数量不匹配 | NCCL_DEBUG=INFO 看 rank 连接 |
确认 --nproc_per_node 正确 |
| 防火墙阻断 | telnet <ip> <port> |
开放 NCCL 端口 |
| PFC 死锁 | 交换机查 PFC pause 计数 | 重启交换机/配置 watchdog |
| GDR 失败 | dmesg \| grep nv_peer_mem |
重载 nvidia-peermem |
| IB 链路 down | ibstatus |
检查线缆/重启 HCA |
| CUDA OOM | nvidia-smi |
减少 batch size |
8.3 nccl-tests 使用和性能评估
1 | # 安装 |
输出解读:
1 | # size count type redop time algbw busbw #wrong |
性能达标判断:

参考基准:
- HDR 200Gb/s IB:理论峰值 ~23 GB/s,合格线 busbw > 18 GB/s
- NDR 400Gb/s IB:理论峰值 ~46 GB/s,合格线 busbw > 37 GB/s
8.4 为什么同节点 GPU 要分配给同一个 TP Group?

关键原因:
- TP AllReduce 频率极高:每个 Transformer 层有 4 次 AllReduce
- NVLink 比 IB 快 36 倍:NVLink 4.0 = 900 GB/s vs IB NDR = 25 GB/s
- DP/PP 通信量相对少:PP 只传激活值,DP 梯度可以异步
1 | 理论 TP 通信耗时对比(GPT-3 一层,bs=1, seq=2048): |
8.5 跨数据中心训练时 NCCL 如何感知网络拓扑?

1 | # 跨 DC 场景常用配置 |
NCCL 拓扑感知逻辑:
- 扫描
/sys/bus/pci设备树,建立 GPU-NIC 亲和关系 - 读取 NVML 报告的 NVLink 连接
- 通过
ibv_query_port获取 IB 端口信息 - 构建加权图,用最短路径算法确定最优 channel 路径
8.6 NCCL Channel — 什么是 Channel?为什么需要多 Channel?

Channel 的本质:
- 一个 NCCL Channel = 一个独立的 Ring(或 Tree)拓扑实例 + 一套 QP + 一套缓冲区
- 每个 Channel 可以使用不同的网卡(多网卡时)或不同的 NVLink 路径
为什么需要多 Channel?
- 隐藏延迟:多 channel 并发流水线,CPU 调度一个时另一个在后台传输
- 利用多网卡:多 channel 分配到不同网卡,聚合带宽 = 网卡数 × 单卡带宽
- 提高 NVLink 利用率:多 channel 使用 NVLink 的多个 lane
- 减少 head-of-line blocking:大消息分片到多 channel 并行传
1 | # 控制 channel 数 |
Channel 数与性能的关系:
1 | channel 太少 → 带宽未充分利用(CPU 调度跟不上) |
速查表
| 知识点 | 关键数字 |
|---|---|
| NVLink 4.0 带宽 | 900 GB/s 双向 |
| IB NDR 带宽 | ~46 GB/s 单向 |
| RDMA 延迟 | ~1-2 μs |
| TCP 延迟 | ~10-100 μs |
| Ring AllReduce 通信量 | 2(N-1)/N × M ≈ 2M |
| ZeRO-3 通信量 | 3M |
| TP AllReduce 次数/层 | 4 次(2前向+2后向) |
| NCCL LL 协议阈值 | ~16 KB |
| busbw = algbw × | AllReduce: 2(N-1)/N |
| Fat-Tree k-ary 交换机数 | 5k²/4 |
| Fat-Tree 最大主机数 | k³/4 |
本文整理自分布式训练网络系统知识,适合 AI 基础设施工程师、MLSys 研究者参考学习。



