GPU 通信技术全景:从 PCIe、NVLink 到 RDMA、EFA 与 NCCL
训练大模型时,通信会取代计算成为瓶颈。这篇文章把 GPU 互联的整条链路一次讲透:PCIe 的事务模型与 BAR、NVLink/NVSwitch 的全互联与在网规约、AMD Infinity Fabric、RDMA/InfiniBand 的 QP 与内存注册、RoCE 的无损以太网三件套、AWS EFA 的 SRD 多路径喷洒、GPUDirect 如何消除 CPU 拷贝,以及 NCCL 如何调度这一切。
这是一篇把 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.0 | 2.5 GT/s | 8b/10b | 0.25 GB/s | ~4 GB/s |
| 2.0 | 5.0 GT/s | 8b/10b | 0.5 GB/s | ~8 GB/s |
| 3.0 | 8.0 GT/s | 128b/130b | ~0.985 GB/s | ~16 GB/s |
| 4.0 | 16 GT/s | 128b/130b | ~1.97 GB/s | ~32 GB/s |
| 5.0 | 32 GT/s | 128b/130b | ~3.94 GB/s | ~64 GB/s |
| 6.0 | 64 GT/s (PAM4) | PAM4+FLIT+FEC | ~7.5 GB/s | ~120 GB/s |
| 7.0 | 128 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 为突破上述限制设计的点对点、缓存一致、高速串行互联。
2.1 物理层次:Link → Sub-link → Lane#
一条 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.0 | Pascal (P100) | 40 GB/s | 4 | 160 GB/s | NRZ ~20 Gbps |
| NVLink 2.0 | Volta (V100) | 50 GB/s | 6 | 300 GB/s | NRZ ~25 Gbps |
| NVLink 3.0 | Ampere (A100) | 50 GB/s | 12 | 600 GB/s | NRZ ~50 Gbps |
| NVLink 4.0 | Hopper (H100) | 50 GB/s | 18 | 900 GB/s | PAM4 ~106 Gbps |
| NVLink 5.0 | Blackwell (B200) | ~100 GB/s | 18 | 1800 GB/s | PAM4 ~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 Access:
cudaDeviceCanAccessPeer()判断两 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.0 | Volta (V100, DGX-2) | 首次实现 16 GPU 全互联(板内) |
| NVSwitch 2.0 | Ampere (A100) | 配合 NVLink 3.0,8 GPU HGX 全互联 |
| NVSwitch 3.0 | Hopper (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。看旧资料时容易混。
| 功能 | NVIDIA | AMD |
|---|---|---|
| GPU↔GPU 高速直连 | NVLink | xGMI |
| 节点内全互联交换 | NVSwitch | xGMI fully-connected mesh |
| CPU↔GPU 一致互联 | NVLink-C2C(Grace Hopper) | Infinity Fabric(MI300A 统一内存) |
| chiplet 片内缝合 | NV-HBI / 片内互联 | IFOP |
| 集合通信库 | NCCL | RCCL |
五、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() 注册一段缓冲区时发生三件事:
- 锁页(pin):把内存锁定在物理内存中,禁止换出/迁移(否则 DMA 时物理地址会变)。
- 建立地址映射:网卡记录虚拟地址与物理地址(或 IOVA)的映射。
- 生成 key:
lkey(本地校验)与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#
| 维度 | InfiniBand | RoCE 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 RC | RoCE v2 | EFA / SRD |
|---|---|---|---|
| 保序 | 硬件保序 | 硬件保序 | 不保序(上层重组) |
| 可靠性 | 是 | 是 | 是(选择性重传) |
| 多路径单流 | 否 | 否 | 是(多路径喷洒) |
| 无损依赖 | 链路信用流控 | 依赖 PFC | 不依赖 PFC |
| 重传 | 较重 | go-back-N | 选择性重传 |
| 拥塞控制 | IB CC | DCQCN | 网卡内自研 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 进显存(通过
cuFileAPI),把“存储 → 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 | 规约后按片分散到各 GPU | ZeRO 梯度分片 |
| 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 数不够没能聚合多链路带宽。
参考资料
- NVIDIA NVLink and NVSwitch — NVIDIA
- NVIDIA Collective Communications Library (NCCL) Documentation — NVIDIA Docs
- GPUDirect RDMA Documentation — NVIDIA Docs
- PCI Express Base Specification — PCI-SIG
- A Cloud-Optimized Transport Protocol for Elastic and Scalable HPC (SRD) — IEEE Micro
- Elastic Fabric Adapter (EFA) User Guide — AWS Documentation
- AMD Instinct MI300 Series Architecture — AMD
- aws-ofi-nccl: NCCL network plugin for libfabric — GitHub
常见问题
为什么 GPU 之间的通信会成为大模型训练的瓶颈?
为什么高性能数据通路都偏爱「写」而不是「读」?
NVLink 和 PCIe 是替代关系吗?
InfiniBand、RoCE 和 AWS EFA 三者的根本差异是什么?
GPUDirect RDMA 没生效会有什么表现?怎么排查?
Ring AllReduce 为什么被称为「带宽最优」?它有什么缺点?
微信扫码
用微信扫一扫,把文章带到聊天或朋友圈。
继续阅读
- 云架构
OpenAI "解绑"微软、牵手 AWS:AI 云战争进入新纪元
2026 年 4 月 27 日微软与 OpenAI 修订协议结束独占关系;两个月前 Amazon 向 OpenAI 投资 500 亿美元;Codex 仓库悄悄合并的 Bedrock GPT-5.4 兼容性修复证实模型已在 AWS 生产环境运行。三件事串起来看:模型正在变成基础设施,独占不可持续,AI 产业权力版图正在重绘。
- 云架构
用 CloudFront + Lambda@Edge 记录失败请求的 5 个坑
我们用双 Lambda@Edge 方案为 CloudFront 实现了完整的请求日志记录。以下是我们踩过的 5 个坑。
- 云架构
使用 Amazon Nova 构建实时音视频 AI
结合 Amazon Nova、Transcribe、Polly 与开源 TEN 框架,构建低延迟的多模态 AI 助手。
- 云架构
Amazon QuickSuite:自然语言数据分析实战指南
手把手教你用 Amazon QuickSuite 连接数据库、构建仪表板,并用自然语言查询数据。