GPU 通信技术全景:从 PCIe、NVLink 到 RDMA、EFA 与 NCCL

训练大模型时,通信会取代计算成为瓶颈。这篇文章把 GPU 互联的整条链路一次讲透:PCIe 的事务模型与 BAR、NVLink/NVSwitch 的全互联与在网规约、AMD Infinity Fabric、RDMA/InfiniBand 的 QP 与内存注册、RoCE 的无损以太网三件套、AWS EFA 的 SRD 多路径喷洒、GPUDirect 如何消除 CPU 拷贝,以及 NCCL 如何调度这一切。

zhuermu··35 分钟
GPUNVLinkNVSwitchRDMAInfiniBandRoCEEFANCCLGPUDirectAI 基础设施

这是一篇把 GPU 互联与通信技术串成一条链路的全景文章。目标不是停留在“带宽多少、能干什么”,而是深入到总线协议、内存模型、报文封装、拥塞控制与集合通信算法这一层。

为什么需要 GPU 通信技术#

一块现代 AI 加速卡(如 NVIDIA H100)的算力高达数百 TFLOPS,但单卡显存只有几十到上百 GB。训练一个千亿/万亿参数大模型,必须把模型和数据切分到成百上千张 GPU 上协同计算。此时通信会取代计算成为瓶颈:

训练一步的时间 ≈ max(计算时间, 通信时间)   (理想重叠情况下)

当模型并行 / 数据并行的梯度同步(AllReduce)跟不上计算速度时,GPU 就会“算完等数据”,利用率(MFU)骤降。因此整个 AI 基础设施的核心命题之一,就是:

如何让数据在 GPU 之间以尽可能高的带宽、尽可能低的延迟流动。

全文的结构,也就是数据流动的层次:节点内(PCIe → NVLink/NVSwitch/Infinity Fabric)、节点间(RDMA/InfiniBand → RoCE → EFA)、贯穿两者的加速机制(GPUDirect),以及在上层调度这一切的大脑(NCCL)。

一、PCIe:一切的通用基石#

即便有了 NVLink,GPU 的枚举、初始化、与 CPU 的控制面交互、与网卡的部分数据通路,仍然走 PCIe。

1.1 从并行共享总线到点对点串行链路#

早期 PCI 是并行共享总线:多设备挂在同一组并行信号线上分时复用。缺点是共享带宽、并行线间时钟偏移(skew)限制频率、扩展性差。PCIe 做了三点范式转变:

  • 点对点:每个设备独占一条到交换结构的链路。
  • 串行差分信令:一个 lane 含 TX/RX 差分对,靠差分消除共模噪声,把频率推到 GHz 级。
  • 交换式结构:通过 Root Complex 和 Switch 构成树形拓扑,类似网络交换机。
              ┌──────────┐
              │   CPU    │
              │  + Root  │   Root Complex:PCIe 拓扑的根
              │ Complex  │
              └────┬─────┘
                   │ (PCIe Link)
          ┌────────┴────────┐
          │   PCIe Switch   │   含上行口与多个下行口
          └──┬───────────┬──┘
             │           │
        ┌────┴───┐   ┌───┴────┐
        │  GPU   │   │  NIC   │   Endpoint:终端设备
        └────────┘   └────────┘

关键点:GPU-GPU 走 PCIe 时,数据要先上行到 Switch 或 Root Complex,再下行到目标 GPU。 同一 Switch 下可做 Switch 内 P2P;跨 Root Complex(跨 NUMA / 跨 socket)还要经过 CPU 间互联(如 UPI),延迟更高。这正是 NVLink 要解决的问题。

1.2 三层协议栈与 TLP#

┌─────────────────────────────────┐
│  事务层 (Transaction Layer)      │  生成/解析 TLP,事务语义、流控、QoS
├─────────────────────────────────┤
│  数据链路层 (Data Link Layer)    │  序号、ACK/NAK、重传、LCRC
├─────────────────────────────────┤
│  物理层 (Physical Layer)         │  串行化、编码、加扰、链路训练
└─────────────────────────────────┘

事务层的基本单位是 TLP(Transaction Layer Packet)。理解性能的关键是 Posted 与 Non-Posted 的区别:

事务类型说明是否需要 Completion
Memory Read读内存/读 MMIO 寄存器是(Non-Posted)
Memory Write写内存/写寄存器否(Posted,发完即走)
Configuration读写配置空间(枚举设备)
Message中断(MSI/MSI-X)、电源管理、错误信号
  • Memory Write 是 Posted:发出后立即认为完成,可流水线化、吞吐高。
  • Memory Read 是 Non-Posted:必须等对方回 Completion TLP,引入 RTT 级延迟,受“飞行中读请求数量”限制。

这解释了一个贯穿全文的工程现象:很多高性能数据通路(GPUDirect、RDMA)都尽量用“写”而非“读”来搬数据。

还有两个影响有效带宽的参数:MPS(Max Payload Size,单个 TLP 最大数据量,常见 128/256/512 B)MRRS(Max Read Request Size)。若 MPS=256B、Header=12B,加上帧定界、序号与 LCRC,协议税约 20~24B,有效率约 256/(256+24) ≈ 91%——MPS 越小,这个比例越差。

链路层负责可靠传输:给每个 TLP 加序号与 LCRC,正确回 ACK、错误回 NAK 触发重传,未被 ACK 的 TLP 留在 Replay Buffer。此外它用 DLLP 维护基于信用的流控——接收方告知发送方还有多少缓冲信用,发送方只在有信用时才发。PCIe 因此天生无损,不靠丢包反压(这一点与后文 RoCE 需要 PFC 模拟无损以太网形成鲜明对比)。

物理层负责 SerDes、加扰与编码。编码演进直接决定了带宽:PCIe 1.0/2.0 用 8b/10b(开销 20%),3.0~5.0 用 128b/130b(开销仅约 1.5%),6.0 起改用 PAM4(一个符号载 2 bit)+ FEC + FLIT 模式。

1.3 各代速率与带宽换算#

版本速率 (per lane)编码单 lane 有效带宽x16 单向
1.02.5 GT/s8b/10b0.25 GB/s~4 GB/s
2.05.0 GT/s8b/10b0.5 GB/s~8 GB/s
3.08.0 GT/s128b/130b~0.985 GB/s~16 GB/s
4.016 GT/s128b/130b~1.97 GB/s~32 GB/s
5.032 GT/s128b/130b~3.94 GB/s~64 GB/s
6.064 GT/s (PAM4)PAM4+FLIT+FEC~7.5 GB/s~120 GB/s
7.0128 GT/s (PAM4)PAM4+FLIT+FEC~15 GB/s~240 GB/s

表中 x16 一列统一按「单 lane 有效带宽 × 16」计算,因此和常见的营销口径略有差异。 PCIe 6.0/7.0 常被标称为 128 / 256 GB/s,那是裸速率聚合值(64 GT/s × 16 ÷ 8 = 128), 没有扣除 FLIT 模式下的 FEC 与 CRC 开销;扣掉之后约为 120 / 240 GB/s。 注意 6.0 起不再用 128b/130b,下面的公式只适用于 3.0~5.0。

适用于 PCIe 3.0~5.0(128b/130b 编码):
单 lane 有效带宽 = 速率(GT/s) × (128/130) / 8  [GB/s]
例:PCIe 4.0 = 16 × (128/130) / 8 ≈ 1.97 GB/s
x16 单向 = 1.97 × 16 ≈ 32 GB/s;全双工双向约 64 GB/s

1.4 BAR 与 MMIO:GPUDirect 的物理基础#

PCIe 设备通过 BAR(Base Address Register) 把自己的内存/寄存器映射到系统物理地址空间,这叫 MMIO。系统枚举时给每个 BAR 分配一段物理地址;CPU 访问这段地址时,Root Complex 把它翻译成 Memory Read/Write TLP 发给设备。反过来,设备做 DMA 时发出的 TLP 带的是系统物理地址(或经 IOMMU 翻译的 IOVA)。

这对 GPU 通信至关重要:

  • GPU 显存可以通过 BAR(尤其 BAR1 / Resizable BAR)暴露到 PCIe 地址空间。
  • 一旦显存对外可寻址,另一块 GPU 或网卡就能直接对它发 Memory Write TLP——这就是 GPUDirect P2P / RDMA 的物理基础。
  • IOMMU(Intel VT-d / AMD-Vi)在设备 DMA 与物理内存之间做地址翻译与隔离;在虚拟化与 P2P 场景下,它的配置直接影响 P2P 是否可用。

1.5 ACS:为什么有时 GPU 间走 PCIe 特别慢#

ACS(Access Control Services) 是一种安全机制,它可以强制要求 Switch 下行口之间的 P2P 流量先上送到 Root Complex 再下发,以便 IOMMU 检查。这在虚拟化中是安全特性,但对 P2P 性能是灾难——本可在 Switch 内直接转的流量被迫绕一大圈。

工程经验:同一 Switch 下两 GPU,关闭 ACS 重定向后可走 Switch 内 P2P;跨 socket 的 GPU P2P 要经 CPU 间互联,带宽受限、延迟高,NCCL 拓扑探测会把它判为低优先级路径。这也是数据中心 GPU 服务器倾向用 PCIe Switch 把 GPU 与 NIC 组织在同一 Switch 下、并精心规划 NUMA 亲和性的原因。

1.6 PCIe 的四道墙#

维度PCIe 的瓶颈
带宽PCIe 5.0 x16 仅 ~64 GB/s 单向,H100 NVLink 达 ~450 GB/s/方向
拓扑树形结构,GPU-GPU 要经 Switch/Root,跨 socket 更绕
一致性不是缓存一致的互联,GPU 间共享数据要显式管理
延迟经 Root Complex 转发,延迟高于直连

二、NVLink:GPU 间的高速直连#

NVLink 是 NVIDIA 为突破上述限制设计的点对点、缓存一致、高速串行互联

一条 NVLink "Link" = 两条方向相反的 Sub-link(全双工)
       ┌──────────────── Link ────────────────┐
GPU A  │  Sub-link (TX) ───────────────►  GPU B │
       │  Sub-link (RX) ◄───────────────        │
       └────────────────────────────────────────┘

每条 Sub-link = 若干条 Lane(差分信号对),由高速 SerDes 驱动

与 PCIe 的关键差别:PCIe 一个端口连一个对端(树形);NVLink 一块 GPU 有十几条独立 Link,可以同时连多个对端,天然适合构建 mesh 或经 NVSwitch 的全互联。

协议同样分三层(协议层 / 数据链路层 / 物理层),关键机制包括:基于 flit(flow control unit) 的传输、信用流控(链路内部无丢包)、CRC + 重放保证可靠,以及地址共享与一致性——NVLink 支持把对端 GPU 显存映射进统一虚拟地址空间(UVA),并在协议层传递一致性/原子操作消息,使多 GPU 能像访问本地内存一样访问对端显存。

2.2 各代演进#

带宽提升来自三个杠杆:单 lane 速率提升(SerDes 升级 + NRZ→PAM4)、每 GPU link 数量增加、引入 NVSwitch 实现全互联。

代际首发架构单 link 双向带宽每 GPU link 数每 GPU 总双向带宽信令 (per lane)
NVLink 1.0Pascal (P100)40 GB/s4160 GB/sNRZ ~20 Gbps
NVLink 2.0Volta (V100)50 GB/s6300 GB/sNRZ ~25 Gbps
NVLink 3.0Ampere (A100)50 GB/s12600 GB/sNRZ ~50 Gbps
NVLink 4.0Hopper (H100)50 GB/s18900 GB/sPAM4 ~106 Gbps
NVLink 5.0Blackwell (B200)~100 GB/s181800 GB/sPAM4 ~212 Gbps

口径说明:上表是 NVIDIA 习惯的双向带宽。H100 的 900 GB/s = 18 link × 50 GB/s(双向), 折合单向约 450 GB/s——已是 PCIe 5.0 x16 单向的 7 倍。 单 link 怎么来的:H100 每条 link 用 2 对差分线,每对 ~106.25 Gbps PAM4, 裸速率单向 ≈ 2 × 106.25 / 8 ≈ 26.5 GB/s,扣掉编码与协议开销后标称 25 GB/s 单向 / 50 GB/s 双向。 注意每代的「每 link 差分对数」也在变,所以不能只看 per-lane 速率倒推。

NVLink-C2C(Chip-to-Chip) 则用于 Grace Hopper(CPU+GPU)与 Blackwell 双 die 之间,提供高带宽、缓存一致的芯片间互联(如 Grace↔Hopper 达 900 GB/s 双向),让 CPU 内存与 GPU 显存共享统一地址空间。

2.3 软件视角#

  • UVA + Peer AccesscudaDeviceCanAccessPeer() 判断两 GPU 能否 P2P,cudaDeviceEnablePeerAccess() 打开后,一块 GPU 的 kernel 可直接解引用另一块 GPU 显存的指针,底层走 NVLink。
  • cudaMemcpyPeer / cudaMemcpyPeerAsync:GPU 间拷贝,有 NVLink 则自动走 NVLink。
  • nvidia-smi topo -m:查看 GPU 间连接类型(NV# 表示经 N 条 NVLink,SYS 表示经 PCIe+CPU,PHB/PXB 表示经 PCIe 桥/Switch)。

三、NVSwitch:节点内全互联与在网规约#

NVLink 解决了“两块 GPU 之间怎么高速连”,但 GPU 数量增加后,靠两两直连无法保证“任意一对都满带宽”:8 块 GPU 两两直连需要 C(8,2) = 28 对链路,link 根本不够分,而且会出现带宽不均衡、中转 GPU 拥塞、扩展性差的问题。

解决思路和网络界一样:引入交换机

3.1 非阻塞交叉开关#

NVSwitch 本质是一颗专用的 NVLink 交换 ASIC,核心是**交叉开关(crossbar)**加上路由与缓冲逻辑:

            NVLink 端口 (一颗 NVSwitch 有几十个)
   in0 ─┐  ┌─ in1 ─┐  ┌─ in2 ─┐        ...
        │  │       │  │       │
   ┌────▼──▼───────▼──▼───────▼────────────┐
   │            Crossbar 交叉开关           │  任意输入可转发到任意输出
   │      + 路由表 / 缓冲 / 仲裁逻辑         │  内部带宽 ≥ 所有端口带宽之和
   └────┬──┬───────┬──┬───────┬────────────┘
        │  │       │  │       │
  out0 ─┘  └─ out1 ─┘  └─ out2 ─┘        ...
  • 非阻塞:内部交换容量不低于所有端口带宽之和,任意端口同时满速收发都不会内部拥塞。
  • 基于目的地址路由:每个包带目标 GPU 标识,查路由表决定转出端口。
  • 低延迟:纯硬件一跳转发,百纳秒量级。
  • 缓冲与仲裁:多输入争同一输出时靠输出端口仲裁与缓冲排队,配合信用流控保证无丢包。

3.2 节点级拓扑#

 GPU0  GPU1  GPU2  GPU3  GPU4  GPU5  GPU6  GPU7
  │││   │││   │││   │││   │││   │││   │││   │││   ← 每块 GPU 的 18 条 NVLink
  │││   │││   │││   │││   │││   │││   │││   │││     被"打散"分配到多颗 NVSwitch
 ┌┴┴┴───┴┴┴───┴┴┴───┴┴┴───┴┴┴───┴┴┴───┴┴┴───┴┴┴┐
 │   NVSwitch 0   NVSwitch 1  ...  NVSwitch K   │
 └───────────────────────────────────────────────┘

每块 GPU 的 link 分散接到多颗 NVSwitch,既避免单点瓶颈,也使任意两块 GPU 之间存在多条并行路径。结果是任意一对 GPU 之间都能达到该 GPU 的全部 NVLink 带宽(H100 约 900 GB/s 双向),且与是哪两块 GPU 无关——不存在”某两块卡之间特别慢”的短板链路,这就是“全互联、无阻塞、带宽均衡”。

需要说明的是:这个 900 GB/s 是单对 GPU 独占通信时的上限,衡量的是”没有短板路径”。 8 卡同时全互联通信时,每块 GPU 的 18 条 link 要分给多个对端,单对实际拿到的带宽自然低于该上限; 非阻塞保证的是交换结构内部不额外制造拥塞,而不是凭空放大总带宽。

正因为没有短板链路,NCCL 的 Ring/Tree 算法跑在这张网上时不会被某一段拖慢——这是 DGX/HGX H100 单机 8 卡能在 AllReduce 中几乎打满带宽的原因。

演进路线:

代际配套 GPU关键变化
NVSwitch 1.0Volta (V100, DGX-2)首次实现 16 GPU 全互联(板内)
NVSwitch 2.0Ampere (A100)配合 NVLink 3.0,8 GPU HGX 全互联
NVSwitch 3.0Hopper (H100)配合 NVLink 4.0;引入 SHARP 在网计算;可外置组网
NVSwitch 4.0+Blackwell (GB200)机柜级 NVL72:72 GPU 单一 NVLink 域

NVL72 把一个机柜内 72 块 GPU 连成单一 NVLink 域,对软件呈现为“一个巨大的 GPU 池”,跨服务器也能用 NVLink 带宽与一致性语义,极大缩小了传统“机内 NVLink、机间 InfiniBand”的两段式延迟差异。

3.3 SHARP:把规约下沉到交换芯片#

传统 AllReduce 中,数据要在 GPU 之间来回搬运、累加,链路上跑了很多份数据。NVSwitch 3.0 引入的 SHARP(NVLS / NVLink SHARP) 改变了这一点:

       GPU0   GPU1   GPU2   GPU3
         \      |     |      /        各 GPU 把数据发给 NVSwitch
           ▼    ▼     ▼     ▼
      ┌──────────────────────────┐
      │  NVSwitch 内置规约引擎     │  在交换芯片里直接做 sum/max 等规约
      │  result = Σ(GPU0..GPU3)   │
      └──────────────────────────┘
           │    │     │     │        规约结果一次性广播回所有 GPU
           ▼    ▼     ▼     ▼
       GPU0   GPU1   GPU2   GPU3

收益是减少数据搬运量、降低延迟,并把规约从 GPU 的 SM 和带宽预算里释放出来。InfiniBand 交换机侧也有对应的 SHARP,思想一致:让网络不只是搬运数据,还参与计算。

运维上,NVSwitch 由 Fabric Manager 服务管理(初始化交换结构、配置路由、健康检查)。多 GPU 节点若 FM 未启动,NVLink 全互联可能不可用,NCCL 会退回 PCIe。NVLink 误码/降速可用 nvidia-smi nvlink -e 或 DCGM 监控捕获——误码率升高会显著拖慢集合通信。

四、AMD Infinity Fabric:一套互联,多种用途#

NVIDIA 的体系里 PCIe、NVLink、NVSwitch 是分立技术;AMD 则用一套统一的 Infinity Fabric(IF) 覆盖从片内到片间的所有互联。它逻辑上分两个平面:

  • SDF(Scalable Data Fabric):数据搬运——内存请求、缓存一致流量、DMA,连接 CPU 核/CCX、内存控制器、IO die、GPU 计算单元。
  • SCF(Scalable Control Fabric):控制面——电源管理、时钟、安全、配置、QoS、遥测。

物理层按距离分两种:

物理层用途特点
IFOP(On-Package)封装内 die 间(chiplet 之间)短距、超高带宽、低功耗
IFIS(Inter-Socket)封装/socket 之间长距,复用 PCIe SerDes 物理通道

IFIS 与 PCIe 复用同一组 PHY/lane,这就是 AMD 平台上著名的 “xGMI / PCIe lane 复用”:同样的引脚,插 GPU 走 PCIe,连另一颗 CPU 走 IF。在 GPU 互联语境下,AMD 把 GPU↔GPU 的链路称为 xGMI,角色等价于 NVLink;8 卡 Instinct 平台(OAM 基板)多用 GPU 间直连的 fully-connected mesh,而非独立交换芯片。

缓存一致性是 Infinity Fabric 的灵魂,也是它与 PCIe 的本质区别。SDF 上每个代理访问内存时,IF 维护一致性目录/协议(MOESI 类模型),保证一个代理写的数据对其他代理可见,无需软件显式 flush。跨 die、跨 socket 访问呈现 NUMA 特性。正因如此,CPU 和 GPU 才能共享统一地址空间——这是 MI300A 架构的基础:

        MI300A 封装内(简化)
   ┌──────────────────────────────────────┐
   │  Zen4 CPU die   ┌─────────────────┐   │
   │       │         │  CDNA3 GPU die  │   │
   │       └──IFOP──┤ (多个 XCD)       │   │
   │                 └─────────────────┘   │
   │        共享 Infinity Cache + HBM3      │  CPU/GPU 统一寻址,一致访问
   └──────────────────────────────────────┘

MI300X 是纯 GPU 版本:8 个 XCD(Accelerator Complex Die,计算 die) 堆叠在 4 个 IOD 之上、通过 IFOP 在封装内互联,配 192GB HBM3,对软件呈现为单一 GPU;MI300A 则在同一封装内集成 CPU + GPU + HBM,消除了 PCIe 上的 H2D/D2H 拷贝。软件栈是 ROCm + RCCL(对标 NCCL,API 高度兼容),跨节点仍配合 RoCE 或 InfiniBand。

注意术语代差:MI200/MI250X 的计算 die 叫 GCD(Graphics Compute Die,每卡 2 个), MI300 系列改称 XCD。看旧资料时容易混。

功能NVIDIAAMD
GPU↔GPU 高速直连NVLinkxGMI
节点内全互联交换NVSwitchxGMI fully-connected mesh
CPU↔GPU 一致互联NVLink-C2C(Grace Hopper)Infinity Fabric(MI300A 统一内存)
chiplet 片内缝合NV-HBI / 片内互联IFOP
集合通信库NCCLRCCL

五、RDMA 与 InfiniBand:跨节点的高速通道#

当训练规模超出单机,GPU 之间的数据就要跨服务器流动。传统 TCP/IP 走内核协议栈,有拷贝、上下文切换、CPU 参与,延迟高、抖动大。

传统 TCP/IP 收一个包:
  网卡 → 内核 sk_buff → 协议栈处理 → 拷贝到用户缓冲 → 应用
  (多次内存拷贝 + 内核态/用户态切换 + CPU 全程参与)

RDMA 收一个包:
  对端网卡 → 直接 DMA 写入本端预注册的用户内存 → 完成
  (零拷贝 + 内核旁路 + CPU 几乎不参与)

RDMA 的三大支柱:Kernel Bypass(内核旁路)Zero Copy(零拷贝)CPU Offload(传输、可靠性、分片重组由网卡硬件完成)。收益是微秒级延迟、接近线速的带宽、极低的 CPU 占用。

5.1 InfiniBand 的架构特点#

┌──────────┐   IB 链路    ┌──────────────┐   IB 链路   ┌──────────┐
│  Server  │─────────────│  IB Switch   │────────────│  Server  │
│  + HCA   │             │ (Subnet 内转发)│            │  + HCA   │
└──────────┘             └──────────────┘             └──────────┘

                         ┌──────┴───────┐
                         │ Subnet Manager│  集中式:分配 LID、计算路由表
                         │     (SM)      │
                         └───────────────┘

IB Switch 基于 LID 做二层硬件直通转发,延迟极低。Subnet Manager 是 IB 的“大脑”——发现拓扑、分配 LID、计算下发转发表,这种集中式管理是 IB 与以太网(分布式自学习)的根本架构差异。链路层用信用流控,因此 IB 网络天生无损

速率代际(网卡通常按 4 lane 聚合):FDR 56G、EDR 100G、HDR 200G、NDR 400G、XDR 800G。

5.2 编程模型:QP、CQ、verbs#

        应用 (用户态)
          │  ① post 一个 WR (Work Request)

   ┌──────────────┐         ┌──────────────┐
   │  Send Queue  │         │ Receive Queue│   ← QP = SQ + RQ
   │    (SQ)      │         │    (RQ)      │
   └──────┬───────┘         └──────┬───────┘
          │ 网卡硬件读取 WQE 执行    │
          ▼                         ▼
   ┌────────────────────────────────────────┐
   │            HCA / RNIC 硬件              │  做 DMA、分片、可靠传输
   └────────────────────────────────────────┘
          │ ② 完成后写一个 CQE

   ┌──────────────┐
   │ Completion Q │  应用 poll CQ 得知操作完成
   └──────────────┘
  • QP(Queue Pair):一对 SQ + RQ,是 RDMA 通信端点,类比 TCP 的 socket。
  • WR/WQE:应用把“要做什么”描述成工作请求 post 到队列,网卡异步执行。
  • CQ/CQE:完成后网卡写完成事件,应用 poll 或事件通知得知——整个 data path 无系统调用
  • doorbell:post 后写网卡的 doorbell 寄存器(MMIO 写)通知硬件有活干了。

5.3 内存注册:地址翻译与安全的基础#

RDMA 让网卡直接读写用户内存,必须解决地址翻译与安全。应用调用 ibv_reg_mr() 注册一段缓冲区时发生三件事:

  1. 锁页(pin):把内存锁定在物理内存中,禁止换出/迁移(否则 DMA 时物理地址会变)。
  2. 建立地址映射:网卡记录虚拟地址与物理地址(或 IOVA)的映射。
  3. 生成 keylkey(本地校验)与 rkey(交给对端;对端做 RDMA 读写本端内存时必须带正确的 rkey)——这是 RDMA 的安全边界。

要让远端直接写本地内存,必须先把 (地址, rkey) 通过带外通道告诉对方。如果注册的不是 CPU 内存而是 GPU 显存,网卡就能直接 DMA 读写显存——这正是 GPUDirect RDMA 的接入点。

5.4 单边 vs 双边、以及 RC/UC/UD#

类别操作远端 CPU 参与说明
双边SEND / RECV接收方须先 post RECV,需双方配合
单边RDMA WRITE / READ / Atomic直接读写远端已注册内存,需事先知道 (地址, rkey)

RDMA WRITE 是单边操作里最快的——类似 PCIe 的 Posted Write,可流水线打满带宽,NCCL 大量使用;RDMA READ 受 round-trip 限制。这与 PCIe“写优于读”一脉相承。

传输服务类型:

类型可靠连接支持单边用途
RC(Reliable Connected)一对一主流,NCCL/MPI 常用
UC(Unreliable Connected)一对一部分少用
UD(Unreliable Datagram)无连接大规模、连接数受限场景

RC 最常用,但每对端点要建一条连接,连接数随规模平方增长(N² 扩展性问题),大集群会消耗大量 QP 资源与网卡缓存。AWS EFA 的 SRD 正是为解决这个问题而设计的。

在 AI 集群里,大规模常用 Fat-Tree 等无阻塞拓扑,并采用 rail-optimized 设计:每台 8 卡服务器的 8 块网卡分别接入 8 个独立网络平面(rail),让同号 GPU 走同一 rail,减少跨 rail 拥塞。

六、RoCE:在以太网上跑 RDMA,代价是自己造无损网络#

InfiniBand 性能强,但要专用 HCA、交换机和布线,成本高、与现有以太网生态割裂。RoCE 把 IB 的传输层与 RDMA 语义原封不动搬到以太网上。

6.1 v1 与 v2#

RoCE v1 用专门的 EtherType(0x8915)直接把 IB 传输层包封进以太网帧,只能在同一二层广播域内通信,不能 IP 路由,现实中已被取代。RoCE v2 把 IB 传输层包封进 UDP(固定目的端口 4791) 再封进 IP:

┌──────────┬─────────┬─────────┬──────────────┬──────────┬──────────┐
│ Ethernet │  IP     │  UDP    │  IB Transport│  RDMA    │ Payload  │
│ Header   │ Header  │ dport=  │  Header (BTH)│  Payload │ ICRC/FCS │
│          │         │  4791   │              │          │          │
└──────────┴─────────┴─────────┴──────────────┴──────────┴──────────┘

可路由,适配标准三层数据中心网络(Clos/Spine-Leaf)。用 UDP 而非 TCP 是因为 RDMA 自己在 IB 传输层做可靠性;UDP 只是个“信封”,其源端口还被用来做 ECMP 多路径哈希。现在说 RoCE 基本都指 v2。

6.2 核心难题:以太网会丢包,而 RDMA 受不了#

以太网默认允许丢包、靠上层重传兜底;但 RoCE 的 RC 最初采用 go-back-N 重传——丢一个包要从该包开始整窗重传,对吞吐是灾难性打击。大规模 incast(多打一)场景下交换机缓冲极易溢出。所以 RoCE 必须把以太网改造成无损以太网,靠三件套:

PFC(Priority Flow Control, 802.1Qbb) 是逐跳背压。普通 PAUSE 帧会把整条链路全停掉,PFC 改进为按优先级暂停:

   上游交换机                     下游交换机
   ┌─────────┐                   ┌─────────┐
   │  发送    │ ───── 数据 ────►  │ 入口缓冲 │
   │          │                   │  快满了! │
   │  暂停发送 │ ◄── PFC PAUSE ─── │ 发 PAUSE │  针对某个优先级队列
   │ 该优先级  │                   │          │
   └─────────┘                   └─────────┘

数据在链路上被逐跳“憋住”而不是被丢弃。但 PFC 有严重副作用:拥塞扩散 / Head-of-Line 阻塞(PAUSE 逐跳向上游传播,一个热点会连累无关流量)、PFC 风暴 / 死锁(配置不当会让 PAUSE 帧互相触发,整个网络僵住)。所以不能单靠 PFC。

ECN 让交换机在不丢包的前提下告知端点拥塞:队列超阈值时在 IP 头标记 CE(Congestion Experienced),接收端网卡收到后生成 CNP 回送发送端。DCQCN 则把这个信号变成网卡硬件里的速率调节算法:收到 CNP 就快速乘性降速,持续无 CNP 则逐步恢复。

机制层次作用比喻
PFC链路级(逐跳)缓冲将满时背压,保证不丢包堵在门口先憋住
ECN端到端信号拥塞时标记包,触发 CNP亮起”前方拥堵”指示灯
DCQCN端到端控速据 CNP 在源头调速率司机看到灯就减速

理想状态是 DCQCN 在源头把速率调好、队列几乎不积压,PFC 极少触发——调参目标是让 ECN 先于 PFC 生效

多路径靠变化 UDP 源端口 + ECMP,但传统 RoCE 一条 RC 连接的流会被哈希到单条路径,单流无法用多路径——这是 RoCE 的固有限制,也是 SRD 要解决的痛点。

6.3 RoCE vs InfiniBand#

维度InfiniBandRoCE v2
网络介质专用 IB 交换机/HCA/线缆标准以太网交换机 + RNIC
无损机制链路层信用流控(天生无损)需 PFC+ECN+DCQCN 人工调优
管理集中式 Subnet Manager分布式以太网
可路由IB 子网内是(IP 路由,跨子网)
成本/生态高,专用生态低,复用以太网生态
调优难度相对省心较高(阈值、缓冲、死锁风险)

一句话:RoCE 用“成熟廉价的以太网生态”换“自己搞定无损网络的调优复杂度”。调好了能接近 IB;调不好(PFC 风暴、丢包)性能塌方。

七、AWS EFA 与 SRD:拥抱有损与乱序的第三条路#

在超大规模多租户云环境里,IB 太封闭,而 RoCE 的 PFC 逐跳背压会引发大范围连锁反应、运维风险极高。AWS 因此自研了 EFA(Elastic Fabric Adapter) 网络接口与 SRD(Scalable Reliable Datagram) 传输协议。

EFA 提供 OS-bypass 的用户态网络访问,挂载在 P 系列(P4d/P5 等)、部分 G 系列与 HPC 实例上,通过 libfabric 暴露给上层。它不是 InfiniBand,也不是标准 RoCE。

7.1 SRD 的三个反向选择#

多路径喷洒(multi-path spraying)

                    ┌──► path 1 ──┐
   发送端 ── 数据包 ─┼──► path 2 ──┼──► 接收端
   (同一条流的包     ├──► path 3 ──┤   (网卡负责重新排序)
    被打散到多条路径) └──► path N ──┘

SRD 把同一条流的包主动喷洒到大量不同路径上,单流也能用满多路径带宽,天然避开热点链路,极大降低拥塞和尾延迟。代价是包会乱序到达。

拥抱乱序:IB/RoCE 的 RC 要求硬件保证按序交付,一旦丢/乱就要 go-back-N 整窗重传。SRD 只保证“可靠送达”,不保证“按序”,排序责任上移到网卡与上层(libfabric / aws-ofi-nccl)。对 NCCL 这类集合通信,很多场景并不要求底层严格保序,省掉保序开销是划算的。

端到端快速重传 + 网卡内拥塞控制:SRD 在网卡硬件里做 ACK 与选择性重传(只重传真正丢失的包),拥塞控制算法基于 RTT 等信号在网卡内运行,不依赖 PFC——因此 AWS 网络不需要无损以太网,规避了 PFC 死锁风险。全部在 Nitro 卡硬件中执行。

维度IB RCRoCE v2EFA / SRD
保序硬件保序硬件保序不保序(上层重组)
可靠性是(选择性重传)
多路径单流是(多路径喷洒)
无损依赖链路信用流控依赖 PFC不依赖 PFC
重传较重go-back-N选择性重传
拥塞控制IB CCDCQCN网卡内自研 CC

7.2 软件栈#

┌──────────────────────────────────────────────┐
│  应用:PyTorch / Megatron                       │
├──────────────────────────────────────────────┤
│  NCCL                                          │
├──────────────────────────────────────────────┤
│  aws-ofi-nccl  (NCCL 网络插件 → libfabric)     │
├──────────────────────────────────────────────┤
│  libfabric  (OFI 抽象:efa provider)          │
├──────────────────────────────────────────────┤
│  EFA 内核驱动 + Nitro 硬件(SRD 协议)           │
└──────────────────────────────────────────────┘

没有 aws-ofi-nccl 这个插件,NCCL 默认只会用内置的 IB/socket 后端,无法用上 EFA 的 SRD。部署要点:EFA 实例需在同一个 cluster 策略的 Placement Group 内才有最佳网络性能;安装 EFA installer(含内核驱动、libfabric、aws-ofi-nccl)后,用 NCCL_DEBUG=INFO 确认日志里出现 NET/OFI 与 EFA provider 字样。

技术哲学
InfiniBand全栈专用、集中管理、链路天生无损——极致性能,但封闭、贵
RoCE复用以太网,靠 PFC/ECN/DCQCN 人工造无损——灵活省钱,但调优难、有死锁风险
EFA / SRD拥抱有损与乱序,多路径喷洒 + 选择性重传 + 网卡内拥塞控制——为超大规模云而生

EFA 的本质创新:把“保证网络无损/有序”的负担,从网络转移到端侧的传输协议上,用海量路径的统计复用换取确定性的低尾延迟。

八、GPUDirect:把 CPU 从数据通路上摘掉#

前面讲的都是“管道”。GPUDirect 是一组让数据绕开 CPU 与系统内存中转的技术。

没有它时,GPU 与网卡之间传数据要经 CPU 内存中转:

【传统路径】
   GPU 显存 ─① cudaMemcpy D2H→ CPU 系统内存(bounce buffer) ─② 网卡 DMA→ 网卡 → 网络
   数据在 PCIe 上走了两趟,占用 CPU 内存带宽,增加延迟

【GPUDirect RDMA 路径】
   GPU 显存 ──(网卡直接 DMA 读写显存)──► 网卡 → 网络
   一趟 PCIe,不经 CPU 内存,CPU 几乎不参与

物理基础就是前面 PCIe 一节讲的 BAR/MMIO:GPU 通过 BAR(尤其 Resizable BAR)把显存映射到 PCIe 物理地址空间,一旦有了总线地址,任何能发 PCIe Memory TLP 的设备就能直接读写显存。

家族成员:

  • GPUDirect P2P:节点内 GPU↔GPU 直接互访显存。有 NVLink/NVSwitch 则走 NVLink(最快),否则走 PCIe P2P(受 ACS 设置约束)。API 是 cudaDeviceCanAccessPeer() / cudaDeviceEnablePeerAccess()
  • GPUDirect RDMA:跨节点核心。内核模块 nvidia-peermem 向 RDMA 子系统注册回调,使 ibv_reg_mr() 能注册 GPU 显存而非仅 CPU 内存;之后 RDMA WRITE/READ 的地址直接指向显存。
  • GPUDirect Storage(GDS):让 NVMe/存储网络直接把数据 DMA 进显存(通过 cuFile API),把“存储 → CPU 内存 → 显存”的两趟变成一趟,对数据集加载与 checkpoint 读写显著降延迟。

把全栈串起来,看一次跨机发送到底发生了什么:

① NCCL 决定从 节点A-GPU0 把数据发到 节点B-GPU0
② 数据已在 GPU0 显存,且该显存已通过 nvidia-peermem 注册给网卡
③ NCCL 经网络插件 post 一个 RDMA WRITE WQE,
   源地址 = 本地 GPU 显存地址,目的 = 对端 GPU 显存地址 + rkey
④ 本地网卡读 WQE → 直接 DMA 读 GPU0 显存(GPUDirect RDMA)
⑤ 网卡切包,经网络(IB / RoCE 无损以太网 / EFA-SRD)送到对端网卡
⑥ 对端网卡收到 → 直接 DMA 写入 节点B-GPU0 显存
⑦ 网卡写 CQE,NCCL poll 到完成
   —— 全程数据没碰过任何一端的 CPU 系统内存

启用条件与排错:任何一环不满足都会“静默回退”到经 CPU 的慢路径——带宽掉一截却不报错。

条件说明
内核模块加载 nvidia-peermem(或 DMABUF 路径)
PCIe 拓扑GPU 与网卡最好在同一 PCIe Switch / 同一 NUMA,跨 socket 会很慢甚至不可用
ACS 设置ACS 重定向会强制 P2P 绕到 Root Complex,需按需关闭
Resizable BAR大块显存 P2P 需要 BAR 覆盖足够地址空间
驱动/固件GPU 驱动与网卡固件版本需匹配

排错工具:nvidia-smi topo -m 看 GPU↔NIC 连接(PIX/PXB 同 Switch 较好,SYS 跨 NUMA 差);NCCL_DEBUG=INFO 日志里确认 GDR 已启用。

九、NCCL:跑在这些道路上的调度大脑#

NCCL 把分布式训练需要的集合操作翻译成具体数据流,自动探测拓扑、选择算法、选最优链路,并用 GPU kernel 高效执行。它是 PyTorch/Megatron 等框架分布式训练的事实标准通信后端。

操作语义训练中的用途
AllReduce所有 GPU 各有一份,规约后结果分发给所有 GPU数据并行梯度同步(最核心)
AllGather收集各片,每个 GPU 都拥有全部拼接结果ZeRO/FSDP 收集参数分片
ReduceScatter规约后按片分散到各 GPUZeRO 梯度分片
Broadcast一个 GPU 的数据复制到所有 GPU初始化广播权重
All-to-All每个 GPU 给每个 GPU 发不同数据MoE 专家路由、序列并行

关键恒等式:AllReduce = ReduceScatter + AllGather。NCCL 正是这样实现高效 AllReduce 的。

9.1 Ring AllReduce 与带宽最优性#

把 N 块 GPU 在逻辑上连成环,每块只和左右邻居通信,数据切成 N 份,分两阶段:ReduceScatter(N-1 步,每步把自己负责的片发给下一个、收上一个的片并累加),然后 AllGather(再传 N-1 步,把每片的最终结果传给所有人)

设总数据量 S,GPU 数 N。每块 GPU 在整个过程中:
  发送数据量 = 2 × S × (N-1)/N  ≈ 2S (当 N 大时趋于常数)
  即每块 GPU 收发的数据量与 N 几乎无关 → "带宽最优"

缺点是步数 = 2(N-1),延迟随 N 线性增长。所以 NCCL 引入 Tree 算法:把 GPU 组织成树,规约沿树向上汇聚到根再向下广播,延迟从 O(N) 降到 O(log N)。实际用的是双二叉树——构造两棵互补的二叉树,让每个节点在一棵树里是中间节点、在另一棵里是叶子,从而同时利用上下行带宽。

Ring:延迟 O(N),带宽最优 → 适合大消息、中等规模
Tree:延迟 O(log N)      → 适合小消息、大规模
NVLS/CollNet:把规约下沉到 NVSwitch 或 IB 交换机的 SHARP 引擎

NCCL 会根据消息大小和规模自动在三者之间选择,也可用 NCCL_ALGO 强制。

9.2 拓扑感知与 channel#

NCCL 的“智能”很大程度来自启动时的拓扑探测:

① 探测系统拓扑:通过 NVML/系统信息发现 GPU、NVLink/NVSwitch 连接、PCIe 树、网卡、NUMA,
   构建带"链路类型与带宽"的图(NVLink > PCIe P2P > 经 CPU > 网络)
② 计算最优 channel:在图上搜索多条 Ring/Tree 路径,尽量走高带宽链路,
   避开跨 NUMA、跨 rail 的瓶颈
③ 分层:节点内用 NVLink/NVSwitch(GPUDirect P2P),节点间用 IB/RoCE/EFA(GPUDirect RDMA)
   典型做法:节点内 ReduceScatter → 跨节点 AllReduce → 节点内 AllGather

channel 是并行的通信流水线:每个 channel 是一个 ring 或一棵 tree 的实例,绑定一组 SM 与一份链路带宽。多 channel 并行才能把多条 NVLink、多个网卡的带宽聚合打满(H100 有 18 条 NVLink,需要多个 channel 才用得满)。NCCL 用 GPU kernel 同时做“通信 + 规约”,数据流过时就地累加,避免额外拷贝与 kernel 启动。

运行时分工:节点内 NCCL kernel 直接经 NVLink/NVSwitch 读写对端显存;跨节点由 CPU 上的 proxy 线程驱动网络插件 post RDMA 操作,但数据本身经 GPUDirect RDMA 直达显存——CPU 只发命令不碰数据。网络插件机制让 NCCL 能支持 IB、RoCE,也能通过 aws-ofi-nccl 接到 libfabric/EFA。

9.3 一次数据并行 step#

① 各 GPU 前向 + 反向,算出本地梯度
② NCCL AllReduce 对所有 GPU 的梯度求和求平均
     - 节点内:NVLink/NVSwitch 上做 ReduceScatter
     - 节点间:IB/RoCE/EFA 上做跨节点规约(可能用 SHARP/NVLS 在网规约)
     - 节点内:AllGather 把结果铺回每块 GPU
③ 各 GPU 用同步后的梯度更新参数
④ 进入下一 step
通信与反向计算尽量重叠(梯度桶 bucketing + 异步),把通信时间藏到计算后面

9.4 常用调优旋钮#

环境变量作用
NCCL_DEBUG=INFO打印拓扑、算法、GDR 是否启用(排错第一步)
NCCL_ALGO强制 Ring / Tree / CollNet / NVLS
NCCL_PROTO选择 LL/LL128/Simple(延迟 vs 带宽权衡)
NCCL_P2P_LEVEL控制 P2P 使用范围
NCCL_NET_GDR_LEVEL控制 GPUDirect RDMA 启用条件
NCCL_MIN/MAX_NCHANNELS调 channel 数以聚合带宽
NCCL_IB_HCA / NCCL_SOCKET_IFNAME指定使用的网卡
NCCL_TOPO_DUMP_FILE导出探测到的拓扑 XML 供检查

十、把全景拼起来#

一台 P5 实例(8×H100)参与大规模训练时,完整图景是这样的:

节点内(单机 8 卡):
   GPU ──NVLink 4.0──► NVSwitch ──► GPU   (GPUDirect P2P,900 GB/s 级)

节点间(跨实例):
   GPU 显存 ──(GPUDirect RDMA)──► EFA 网卡
        ══ SRD 多路径喷洒 over 以太网底座 ══►
   EFA 网卡 ──(GPUDirect RDMA)──► GPU 显存

调度层:
   NCCL(拓扑感知)+ aws-ofi-nccl + libfabric
   - 节点内 ReduceScatter 走 NVLink/NVSwitch
   - 跨节点 AllReduce 走 EFA/SRD
   - 节点内 AllGather 铺回

每一层各自的角色:

  • PCIe 提供可寻址性(BAR),让别的设备能打到显存;同时承载控制面。
  • NVLink / NVSwitch / Infinity Fabric 提供节点内高速通道与全互联,并能在交换芯片里做规约。
  • RDMA(IB / RoCE / EFA) 提供跨节点通道,三者代表三种关于“无损与有序”的工程哲学。
  • GPUDirect 是把各层焊接成端到端通路的黏合剂——没有它,再快的管道两端也要被 CPU 内存拷贝拖累。
  • NCCL 在上层做拓扑感知的算法选择与调度,把这一切变成一次 AllReduce 调用。

理解这条链路的价值在于:当训练跑不满带宽时,你能沿着它逐层定位——是 ACS 挡住了 P2P,是 Fabric Manager 没起来导致退回 PCIe,是 GDR 静默回退到了 bounce buffer,是 PFC 阈值配错引发拥塞扩散,还是 channel 数不够没能聚合多链路带宽。

参考资料

  1. NVIDIA NVLink and NVSwitch — NVIDIA
  2. NVIDIA Collective Communications Library (NCCL) Documentation — NVIDIA Docs
  3. GPUDirect RDMA Documentation — NVIDIA Docs
  4. PCI Express Base Specification — PCI-SIG
  5. A Cloud-Optimized Transport Protocol for Elastic and Scalable HPC (SRD) — IEEE Micro
  6. Elastic Fabric Adapter (EFA) User Guide — AWS Documentation
  7. AMD Instinct MI300 Series Architecture — AMD
  8. aws-ofi-nccl: NCCL network plugin for libfabric — GitHub

常见问题

为什么 GPU 之间的通信会成为大模型训练的瓶颈?
一块 H100 的算力高达数百 TFLOPS,但单卡显存只有几十到上百 GB,训练千亿/万亿参数模型必须把模型和数据切分到成百上千张卡上协同计算。理想重叠情况下,训练一步的时间约等于 max(计算时间, 通信时间)——当梯度同步(AllReduce)跟不上计算速度时,GPU 就会「算完等数据」,MFU(算力利用率)骤降。
为什么高性能数据通路都偏爱「写」而不是「读」?
因为 PCIe 的 Memory Write 是 Posted(投递型)事务,发送方发出后立即认为完成、不等应答,因此可以流水线化、打满带宽;而 Memory Read 是 Non-Posted,必须等对端返回 Completion TLP,受 round-trip 延迟和「飞行中读请求数量」限制。RDMA 同理:RDMA WRITE 是单边投递型操作,吞吐远优于 RDMA READ,所以 NCCL 等集合通信库大量使用 WRITE。
NVLink 和 PCIe 是替代关系吗?
不是,两者并存、各司其职。GPU 仍然通过 PCIe 被 CPU 枚举和管理、与网卡/存储交互(控制面与部分数据面);GPU 之间的大流量数据走 NVLink。带宽差距很大:PCIe 5.0 x16 单向约 64 GB/s,而 H100 的 NVLink 4.0 单向约 450 GB/s,是前者的 7 倍。
InfiniBand、RoCE 和 AWS EFA 三者的根本差异是什么?
是三种不同的工程哲学。InfiniBand 全栈专用、集中式 Subnet Manager 管理、链路层信用流控天生无损,性能极致但封闭且贵。RoCE 复用以太网生态,靠 PFC + ECN + DCQCN 人工把以太网改造成无损网络,成本低但调优难、有 PFC 死锁风险。EFA/SRD 则反向选择:不追求网络无损,拥抱乱序,用多路径喷洒加选择性重传和网卡内拥塞控制,把可靠性负担从网络转移到端侧传输协议。
GPUDirect RDMA 没生效会有什么表现?怎么排查?
最危险的是它会「静默回退」到经 CPU bounce buffer 的慢路径——带宽掉一截却不报错。排查要点:确认加载了 nvidia-peermem(或 DMABUF 路径)内核模块;用 nvidia-smi topo -m 检查 GPU 与网卡是否在同一 PCIe Switch / 同一 NUMA(PIX/PXB 较好,SYS 跨 NUMA 很差);检查 PCIe ACS 重定向是否需要关闭、Resizable BAR 是否够大、驱动与网卡固件版本是否匹配。最后必须用 NCCL_DEBUG=INFO 看日志确认 GDR 真的启用了。
Ring AllReduce 为什么被称为「带宽最优」?它有什么缺点?
设总数据量 S、GPU 数 N,Ring AllReduce 分 ReduceScatter 和 AllGather 两阶段各 N-1 步,每块 GPU 全程发送的数据量约为 2S(N-1)/N,当 N 较大时趋于常数 2S——即每卡通信量与 GPU 数几乎无关,因此带宽最优。缺点是总步数为 2(N-1),延迟随 N 线性增长,所以在几百上千卡规模下传小消息很吃亏。NCCL 因此引入延迟为 O(log N) 的双二叉树算法,并按消息大小和规模自动在 Ring / Tree / NVLS 之间选择。
分享这篇文章 微博 X LinkedIn
微信扫码

用微信扫一扫,把文章带到聊天或朋友圈。

继续阅读