RDMA 网络与分布式训练

需要在云原生 GPU 集群上用 RDMA(RoCE/IB)+NCCL 做多机多卡分布式训练,或排查 NCCL/RDMA 网络问题、确认 CubeStudio 的 RDMA 资源配置方式时阅读。

01-架构原理 / 网络与分布式训练
RDMARoCEInfiniBandIBNCCLNCCL_IB_HCANCCL_SOCKET_IFNAMENCCL_IB_GID_INDEXNCCL_IB_DISABLEPyTorchJob分布式训练distributed trainingofed_infoshow_gidsnvidia-smiIPC_LOCK

RDMA 网络与分布式训练

⚠️ 重要:本文正文("环境验证"到"关键参数说明")以百度智能云 CCE 为示例(CCE RDMA Device Plugin、registry.baidubce.com 镜像、PFS 并行文件存储等),属于通用 RDMA / NCCL 参考资料,并非 CubeStudio 平台的原生组件。请勿把 CCE RDMA Device Plugincsi-clusterfilepluginbaidu.com/a100_80g_cgpu 等当成本平台自带能力。CubeStudio 自身的 RDMA 支持方式见文末「CubeStudio 中的原生 RDMA 支持」一节。

概述

RDMA(Remote Direct Memory Access,远程直接内存访问)是新一代网络通信技术,允许计算机之间直接进行内存到内存的数据传输,绕过操作系统内核与 CPU 的处理开销。在大规模分布式训练中,RDMA 可有效降低网络传输的服务器端数据处理延迟,实现高吞吐、低延迟的网络通信,从而提升训练效率。

本文介绍在云原生 AI 环境下使用 RDMA 网络进行分布式训练的通用方法。

说明:

  1. 由于 RDMA 网络的特殊性,以下示例在自建 K8s 集群中可能无法直接适用。
  2. IB 与 RoCE 在使用上几乎无区别,如无特别说明以下均以 RoCE 为例,IB 在应用侧无需更改。
  3. 业务镜像中需要包含 NCCL 依赖库,推荐使用 NVIDIA GPU Cloud(NGC)提供的基础镜像。NGC 基础镜像通常已内置 NCCL,并预先配置和优化了常用深度学习框架与工具,可简化设置过程。

使用前提(通用 RDMA 参考)

  • 已创建集群,且集群中至少有 2 台具有 RDMA 网络的 GPU 实例。
  • GPU 实例镜像中包含 OFED 和 NVIDIA 驱动(公有云一般有预装 OFED 驱动的 GPU 镜像,免去手动安装)。
  • 集群已安装对应的 RDMA Device Plugin、GPU Manager、AI Job Scheduler 和深度学习框架 Operator 等组件。

GPU 实例 / 驱动 / 设备插件等部署前置工作,可参考 02-部署安装 段(GPU 与集群准备相关文档)。

环境验证

登录集群内具有 RDMA 网络的 GPU 节点,运行以下命令验证主机环境。

验证 OFED 驱动

$ ofed_info -s          # 查看 RoCE/OFED 驱动版本
MLNX_OFED_LINUX-5.8-1.1.2.1:

验证 NVIDIA GPU 驱动

$ nvidia-smi            # 查看 NVIDIA GPU 驱动与显卡状态
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.141.03   Driver Version: 470.141.03   CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  NVIDIA A100-SXM...  On   | 00000000:53:00.0 Off |                    0 |
| N/A   29C    P0    64W / 400W |      0MiB / 81251MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
| ... (此处省略 GPU 1~7,A100-SXM 8 卡) ...                                   |
+-----------------------------------------------------------------------------+

(示例为 8 卡 A100-SXM 节点,驱动版本 470.141.03、CUDA 11.4。)

查询 RDMA 网卡(GID)

$ show_gids
DEV     PORT  INDEX  GID                                       IPv4          VER  DEV
---     ----  -----  ---                                       ------------  ---  ---
mlx5_0  1     0      fe80:0000:0000:0000:f820:20ff:fe28:c769                 v1   eth0
mlx5_0  1     2      0000:0000:0000:0000:0000:ffff:0a00:3c03   10.0.60.3     v1   eth0
mlx5_1  1     2      0000:0000:0000:0000:0000:ffff:190b:8002   25.11.128.2   v1   eth1
mlx5_2  1     2      0000:0000:0000:0000:0000:ffff:190b:8022   25.11.128.34  v1   eth2
...
mlx5_8  1     2      0000:0000:0000:0000:0000:ffff:190b:80e2   25.11.128.226 v1   eth8

show_gids 列出每张 RDMA 网卡(mlx5_x)的 GID 表,后续配置 NCCL_IB_HCANCCL_IB_GID_INDEX 时需参考此输出。其中 mlx5_0 通常是 TCP 网络的主网卡,mlx5_1~`mlx5_8` 为 RoCE 数据网卡。

提交任务

NCCL 是 NVIDIA 的集合通信库,能实现 Collective 通信和点对点通信,内部已实现 RDMA 通信。NCCL 可根据环境中网卡类型和拓扑关系自行选择最优通信路径,目前主流分布式训练框架均已支持 NCCL。

下面介绍如何通过 YAML(或控制台)方式提交基于 NCCL 的 RDMA 分布式训练任务。

YAML 方式提交任务

前置:已通过 kubectl 连接到 Kubernetes 集群。

以下是一个 swin-transformer 基于 NCCL 的 PyTorch 分布式训练任务示例(PyTorchJob,Master + Worker 各 1 副本,每副本 8 卡):

apiVersion: "kubeflow.org/v1"
kind: "PyTorchJob"
metadata:
  name: "pytorch-swin-transformer-nccl"
spec:
  pytorchReplicaSpecs:
    Master:
      replicas: 1
      restartPolicy: OnFailure
      template:
        metadata:
          annotations:
            sidecar.istio.io/inject: "false"   # 训练 Pod 不注入 istio sidecar
        spec:
          containers:
            - name: pytorch
              image: registry.baidubce.com/cce-ai-native/swin-transformer-torch:v2.0   # 示例镜像(百度云),自建集群请替换为含 NCCL 的镜像(如 NGC)
              imagePullPolicy: IfNotPresent
              command:
              - /bin/sh
              - -c
              - python -m torch.distributed.launch --nproc_per_node 8 --nnodes $WORLD_SIZE --node_rank $RANK --master_addr $HOSTNAME --master_port $MASTER_PORT main.py --cfg configs/swin/swin_large_patch4_window7_224_22k.yaml --pretrained swin_large_patch4_window7_224_22k.pth --data-path /imagenet --batch-size 128 --accumulation-steps 2
              env:
                - name: NCCL_DEBUG
                  value: "INFO"
                - name: NCCL_IB_DISABLE
                  value: "0"           # 0 = 启用 IB/RoCE 传输
              securityContext:
                capabilities:
                  add: [ "IPC_LOCK" ]  # 锁页内存,RDMA 必需
              resources:
                limits:
                  nvidia.com/gpu: 8
                  rdma/hca: 1          # 申请 RDMA 资源
              volumeMounts:
                - mountPath: /imagenet
                  name: dataset
                - mountPath: /dev/shm
                  name: cache-volume   # 共享内存,供 IPC 使用
          schedulerName: volcano
          volumes:
            - name: dataset
              persistentVolumeClaim:
                claimName: imagenet-22k-pvc
            - emptyDir:
                medium: Memory
              name: cache-volume
    Worker:
      replicas: 1
      restartPolicy: OnFailure
      template:
        metadata:
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          containers:
            - name: pytorch
              image: registry.baidubce.com/cce-ai-native/swin-transformer-torch:v2.0
              imagePullPolicy: IfNotPresent
              command:
              - /bin/sh
              - -c
              - python -m torch.distributed.launch --nproc_per_node 8 --nnodes $WORLD_SIZE --node_rank $RANK --master_addr $MASTER_ADDR --master_port $MASTER_PORT main.py --cfg configs/swin/swin_large_patch4_window7_224_22k.yaml --pretrained swin_large_patch4_window7_224_22k.pth --data-path /imagenet --batch-size 128 --accumulation-steps 2
              env:
                - name: NCCL_DEBUG
                  value: "INFO"
                - name: NCCL_IB_DISABLE
                  value: "0"
              securityContext:
                capabilities:
                  add: [ "IPC_LOCK" ]
              resources:
                limits:
                  nvidia.com/gpu: 8
                  rdma/hca: 1
              volumeMounts:
                - mountPath: /imagenet
                  name: dataset
                - mountPath: /dev/shm
                  name: cache-volume
          schedulerName: volcano
          volumes:
            - name: dataset
              persistentVolumeClaim:
                claimName: imagenet-22k-pvc
            - emptyDir:
                medium: Memory
              name: cache-volume
---
# 以下 PV/PVC 使用百度云并行文件存储 PFS(csi-clusterfileplugin),属示例存储,自建集群请替换为 NFS/JuiceFS 等
apiVersion: v1
kind: PersistentVolume
metadata:
  name: imagenet-22k-pv
spec:
  accessModes:
  - ReadWriteMany
  storageClassName:
  capacity:
    storage: 100Gi
  csi:
    driver: csi-clusterfileplugin
    volumeHandle: data-id
    volumeAttributes:
      parentDir: /            # 必填,自定义路径
      path: ""                # 必填,PFS 挂载路径(相对于 parentDir)
      clusterIP: ""           # 必填,PFS 实例的 endpoint
      clusterPort: "8888"     # 必填,当前端口固定为 8888
      clientID: ""            # 非必填,PFS 实例的 id
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: imagenet-22k-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteMany
  storageClassName:
  resources:
    requests:
      storage: 100Gi

NCCL 关键参数说明

NCCL 通过环境变量来启用 RDMA 特性,主要变量如下表。带 * 号的变量在百度 CCE 等托管环境下会被平台基于内部经验自动注入推荐值,无需手动填写(自建集群通常需要自己设置)。

含义 备注
NCCL_IB_DISABLE 0 / 1 0 表示使用 IB/RoCE 传输;1 表示禁止 NCCL 使用 IB/RoCE,退回到 IP 套接字(TCP)
NCCL_IB_HCA * mlx5_1 ~ mlx5_8 指定使用哪些 RDMA 接口进行通信。按套餐/卡数填对应值:8 卡 RoCE 填 mlx5_1mlx5_8,4 卡填 mlx5_1mlx5_4,以此类推。注:mlx5_0 通常是 TCP 主网卡
NCCL_SOCKET_IFNAME * eth0 指定使用哪个 IP 接口进行控制面通信。注:容器内默认是 eth0
NCCL_IB_GID_INDEX * 动态值 RoCE 模式中使用的全局 GID 索引,取值参考 show_gids 命令输出。注:通过容器网络使用 RoCE 时,CNI 插件会为容器创建对应数量的子网卡,GID INDEX 动态生成
NCCL_IB_TIMEOUT * 22 网络断点重连超时时间
NCCL_IB_QPS_PER_CONNECTION * 8 每个 IB QP 连接的连接数
NCCL_DEBUG INFO 控制 NCCL 输出的调试信息,常用于排障

托管环境(如百度 CCE)会在任务运行时自动检测容器的 RoCE 环境,为容器内 PID=1 的进程自动注入 NCCL_IB_HCANCCL_SOCKET_IFNAMENCCL_IB_GID_INDEXNCCL_IB_TIMEOUTNCCL_IB_QPS_PER_CONNECTION 等环境变量。由 PID 1 创建的子进程会继承这些变量,但通过 sh 启动的进程可能无法继承。若用户在 YAML 中已显式声明这些变量,则平台不再自动注入。

为了在 rank 之间共享数据,NCCL 需要为 IPC 和固定(页面锁定)内存共享系统内存,需要在 YAML 中配置:

              securityContext:
                capabilities:
                  add: [ "IPC_LOCK" ]        # 使能进程间通信(锁页内存)
              resources:
                limits:
                  baidu.com/a100_80g_cgpu: 8  # 示例 GPU 资源名(百度云专有),通用环境为 nvidia.com/gpu
                  rdma/hca: 1                 # 使能 RDMA 资源
              volumeMounts:
                - mountPath: /imagenet
                  name: dataset
                - mountPath: /dev/shm         # 用 emptyDir 提供足够共享内存供 IPC
                  name: cache-volume
          volumes:
            - name: dataset
              persistentVolumeClaim:
                claimName: imagenet-22k-pvc
            - emptyDir:
                medium: Memory
              name: cache-volume

上例依赖开源数据集 ImageNet-22K,需提前将数据集拷贝到共享存储(示例用百度云 PFS)的挂载目录中。自建集群可改用 NFS / JuiceFS / Alluxio 等共享存储,详见 算力统筹与分布式存储.md

CubeStudio 中的原生 RDMA 支持

CubeStudio 平台本身已内置 RDMA 资源的申请与注入能力,无需依赖某个云厂商的专有插件名。相关实现:

  • RDMA 资源类型映射myapp/config.pyRDMA_RESOURCE 把 RDMA 类型映射到 K8s 扩展资源名:
    • ibrdma/hca(IB 交换机实现的 RDMA)
    • rocerdma/shared(RoCE 实现的 RDMA)
    • 默认资源名 RDMA_RESOURCE_NAME = 'rdma/hca'(见 myapp/config.py:1278-1283)。

      这里的资源名是平台自定义约定,需与集群实际安装的 RDMA Device Plugin 暴露的扩展资源名一致。

  • 资源解析myapp/utils/core.py:1678get_rdma(resource_rdma) 解析任务的 RDMA 申请值。支持形如 1(roce) / 2(ib) 的写法——括号内若是 roce/ib 等类型词,会被映射成对应的资源名;返回 (数量, 类型, 资源名)
  • 自动注入 IPC_LOCK 与资源限制myapp/utils/py/py_k8s.pyrdma_num > 0 时会自动给容器 securityContext 追加 IPC_LOCK capability(py_k8s.py:1259-1262),并把 RDMA 资源加入容器的 requests/limits(py_k8s.py:1206-1208)。这与上文示例 YAML 里手写的 IPC_LOCK + rdma/hca: 1 是等价目的,只是由平台自动完成。
  • 是否启用 RDMA 一般在项目组配置中开启(见 RDMA_RESOURCE_NAME 注释)。

具体行为以源码为准;上述为帮助定位的导航说明。

最后更新 2026-07-04完整文档以官方仓库为准:GitHub Wiki