GPU 互联架构
节点内互联(NVLink)
NVLink 技术演进
| 版本 | 产品 | 带宽(双向/GPU对) | 拓扑 |
|---|---|---|---|
| NVLink 1.0 | P100 | 160 GB/s | 部分互联 |
| NVLink 2.0 | V100 | 300 GB/s | 全互联(NVSwitch) |
| NVLink 3.0 | A100 | 600 GB/s | 全互联(NVSwitch) |
| NVLink 4.0 | H100 | 900 GB/s | 全互联(NVSwitch) |
NVSwitch 全互联
8 张 GPU + 6 个 NVSwitch 芯片实现全互联:
任意两张 GPU 间带宽(A100):
直连:600 GB/s
经 NVSwitch:600 GB/s(无性能损失)
对比 PCIe:
PCIe 4.0 x16:64 GB/s(双向)
NVLink 3.0:600 GB/s(快 9 倍以上)验证 NVLink 状态
bash
# 查看 NVLink 拓扑
nvidia-smi topo -m
# 输出示例:
# GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
# GPU0 X NV12 NV12 NV12 NV12 NV12 NV12 NV12
# GPU1 NV12 X NV12 NV12 NV12 NV12 NV12 NV12
# ...
# NV12 = NVLink 12 条链路连接
# 测试 NVLink 带宽
/usr/local/cuda/samples/1_Utilities/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest节点间互联(InfiniBand)
InfiniBand 技术规格
| 规格 | 带宽 | 延迟 | 典型产品 |
|---|---|---|---|
| EDR(100Gbps) | 12.5 GB/s | ~600ns | Mellanox ConnectX-5 |
| HDR(200Gbps) | 25 GB/s | ~600ns | Mellanox ConnectX-6 |
| NDR(400Gbps) | 50 GB/s | ~500ns | Mellanox ConnectX-7 |
| XDR(800Gbps) | 100 GB/s | ~500ns | 下一代(规划中) |
RDMA 通信原理
传统 TCP/IP 通信:
应用 → 系统调用 → 内核协议栈 → 网卡驱动 → 网卡
延迟:~10-100μs,CPU 参与全程
RDMA 通信:
应用 → 直接操作网卡(绕过内核)→ 网卡
延迟:~600ns,CPU 几乎不参与
RDMA 三种实现:
InfiniBand:原生 RDMA,性能最好
RoCE v2:以太网上的 RDMA,需无损网络
iWARP:TCP 上的 RDMA,性能较差InfiniBand 集群配置
bash
# 安装 MLNX_OFED 驱动
./mlnxofedinstall --all --force
# 验证 IB 网卡状态
ibstat
# 关注:State: Active,Physical state: LinkUp
# 查看 IB 网络拓扑
ibnetdiscover | head -50
# 测试 IB 带宽
# 服务端
ib_write_bw -d mlx5_0 -i 1
# 客户端
ib_write_bw -d mlx5_0 -i 1 <server-ip>
# 测试 IB 延迟
ib_write_lat -d mlx5_0 -i 1 <server-ip>分布式训练通信
NCCL(NVIDIA Collective Communications Library)
NCCL 是 GPU 集群分布式训练的核心通信库:
python
# PyTorch 分布式训练示例
import torch
import torch.distributed as dist
import torch.nn as nn
from torch.nn.parallel import DistributedDataParallel as DDP
def setup(rank, world_size):
"""初始化分布式环境"""
dist.init_process_group(
backend='nccl', # 使用 NCCL 后端
init_method='env://', # 通过环境变量初始化
world_size=world_size,
rank=rank
)
def train(rank, world_size):
setup(rank, world_size)
# 将模型移到对应 GPU
device = torch.device(f'cuda:{rank}')
model = MyModel().to(device)
# 包装为 DDP 模型
model = DDP(model, device_ids=[rank])
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
for epoch in range(num_epochs):
for batch in dataloader:
inputs, labels = batch
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward() # 自动 AllReduce 梯度
optimizer.step()
dist.destroy_process_group()
# 启动(每台机器上运行)
# torchrun --nproc_per_node=8 --nnodes=8 \
# --node_rank=0 --master_addr=node0 --master_port=29500 \
# train.pyNCCL 集合通信操作
python
import torch
import torch.distributed as dist
# AllReduce:所有节点的梯度求和,结果广播到所有节点
# 用于数据并行训练的梯度同步
tensor = torch.ones(1024).cuda()
dist.all_reduce(tensor, op=dist.ReduceOp.SUM)
# AllGather:收集所有节点的数据
output = [torch.zeros(1024).cuda() for _ in range(world_size)]
dist.all_gather(output, tensor)
# Broadcast:将 rank 0 的数据广播到所有节点
dist.broadcast(tensor, src=0)
# Scatter:将数据分发到各节点
if rank == 0:
scatter_list = [torch.ones(256).cuda() * i for i in range(world_size)]
else:
scatter_list = None
output = torch.zeros(256).cuda()
dist.scatter(output, scatter_list, src=0)NCCL 性能调优
bash
# 设置 NCCL 环境变量
export NCCL_DEBUG=INFO # 开启调试日志
export NCCL_IB_DISABLE=0 # 启用 InfiniBand
export NCCL_IB_HCA=mlx5_0,mlx5_1 # 指定 IB 网卡
export NCCL_SOCKET_IFNAME=eth0 # 指定以太网接口
export NCCL_TREE_THRESHOLD=0 # 强制使用 Ring AllReduce
# 测试 NCCL 性能
git clone https://github.com/NVIDIA/nccl-tests
cd nccl-tests && make MPI=1 MPI_HOME=/usr/local/mpi CUDA_HOME=/usr/local/cuda
# 运行 AllReduce 测试
mpirun -np 16 -H node0:8,node1:8 \
./build/all_reduce_perf -b 8 -e 8G -f 2 -g 1网络性能基准
典型 8 节点(64 GPU)集群 AllReduce 带宽:
消息大小 InfiniBand HDR RoCE 100GbE
1MB ~18 GB/s ~8 GB/s
100MB ~22 GB/s ~11 GB/s
1GB ~23 GB/s ~12 GB/s
训练吞吐影响:
通信效率 = 计算时间 / (计算时间 + 通信时间)
目标:通信效率 > 90%(通信不成为瓶颈)