基于eRDMA进行GPU多机训练

更新时间:
复制 MD 格式

GPU 多机训练的瓶颈常在节点间通信,RoCE、InfiniBand 专网又成本高昂。在搭载 GPU 的集群上启用阿里云弹性 RDMA(eRDMA),无需专网即可在 VPC 内获得高吞吐、低延迟通信,配合 Arena 提交 PyTorch 分布式作业加速训练。

适用范围

方案说明

eRDMA 在普通 VPC 网络下提供 RDMA 直通能力,可绕过内核协议栈直接进行节点间内存读写,显著降低通信延迟、提升吞吐,从而缓解多机训练的网络瓶颈。

本文的整体操作流程如下:

  1. 安装 ACK eRDMA Controller 组件,使集群能够识别并调度 eRDMA 资源。

  2. 创建并配置 GPU 节点池。

  3. 验证节点上的 GPU 与 eRDMA 资源。

  4. 通过 Arena 提交训练作业并验证eRDMA加速。

操作步骤

步骤一:安装 ACK eRDMA Controller 组件

请在创建 eRDMA/GPU 节点池前,先安装 ACK eRDMA Controller 组件。若安装组件前集群中已有节点,需先确保节点池已按步骤二配置,再将这些节点从节点池中移除并重新添加,eRDMA 才能生效。

说明
  • 如果集群网络插件为 Terway,还需配置 Terway 的网卡白名单,避免 Terway 修改 eRDMA 网卡。配置方式请参见 为弹性网卡(ENI)配置白名单

  • 当节点存在多张网卡时,ACK eRDMA Controller 为附加的 eRDMA 网卡配置路由时,默认采用比同网段网卡更低的路由优先级(默认值 200)。如需手动配置网卡,请注意避免路由冲突。

  1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,单击组件管理

  3. 组件管理页面,单击网络页签,定位 ACK eRDMA Controller 组件,按照页面提示配置组件并完成安装。主要配置项如下:

    配置项

    说明

    preferDriver驱动类型

    选择集群节点上使用的 eRDMA 驱动类型。GPU场景需选择 ofed

    关于驱动类型的详细说明,请参见 启用eRDMA

    是否为Pod分配节点全部eRDMA设备

    可选值:

    • True(勾选):为 Pod 分配节点上所有 eRDMA 设备。GPU场景需勾选。

    • False(不勾选):Pod 根据 NUMA 拓扑分配一个 eRDMA 设备。节点需开启 CPU Static Policy 才能保证 Pod 和设备的固定 NUMA 分配。配置方式请参见 创建和管理节点池

安装完成后,在左侧导航栏选择工作负载 > 容器组,选择命名空间 ack-erdma-controller,查看 Pod 运行状态,确认组件运行正常。

步骤二:创建并配置 GPU 节点池

  1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择节点管理 > 节点池

  3. 单击创建节点池,主要配置如下。更多配置,请参考创建和管理节点池

    1. 配置节点池镜像:在实例和镜像 > 操作系统参数栏,选择云市场镜像中的 Alibaba Cloud Linux 3 64 位(预装 eRDMA 软件栈)镜像,该镜像使用cgroup v2。不同可用区的镜像 ID 与版本信息请参考云市场镜像详情

    2. 配置 GPU 节点驱动版本:在高级选项(选填) > 节点标签(Labels)参数栏添加标签,ack.aliyun.com/nvidia-driver-version580.126.09

    3. 配置关闭 PCIe ACS (Access Control Services) 功能的脚本:关闭 PCIe ACS 可提升 GPU 与 eRDMA 网卡间的 P2P 通信能力。在高级选项(选填) > 实例预自定义数据中填写以下脚本,使节点在启动时自动关闭 PCIe ACS。

      config_disable_acs_service(){
              cat << 'EOF' > /usr/bin/disable_pcie_acs
      #!/bin/bash
      ret=0
      found_acs_pci=0
      for BDF in $(lspci -d "*:*:*" | awk '{print $1}'); do
        # skip if it doesn't support ACS
        setpci -v -s ${BDF} ECAP_ACS+0x6.w > /dev/null 2>&1
        if [ $? -ne 0 ]; then
          continue
        else
          found_acs_pci=1
          setpci -v -s ${BDF} ECAP_ACS+0x6.w=0000
          if [ $? -eq 0 ]; then
            echo "[SUCCESS] Disabled ACS on ${BDF}"
          else
            echo "[ERROR] Failed to Disable ACS on ${BDF}"
            ((ret++))
          fi
        fi
      done
      if [ $found_acs_pci -eq 0 ]; then
        echo "[SKIP] no device found that supports ACS"
      fi
      exit $ret
      EOF
          chmod +x /usr/bin/disable_pcie_acs
       
          # 创建 systemd service 文件
          cat << 'EOF' > /etc/systemd/system/disable_pcie_acs.service
      [Unit]
       
      Description=Disable PCIe Access Control Services (ACS)
      After=multi-user.target
       
      [Service]
      Type=oneshot
      ExecStart=/usr/bin/disable_pcie_acs
      RemainAfterExit=yes
       
      [Install]
      WantedBy=multi-user.target
      EOF
       
          # 重新加载 systemd 配置并设置开机自启动
          systemctl daemon-reload
          systemctl enable disable_pcie_acs.service
          systemctl start disable_pcie_acs.service
          echo "disable_pcie_acs service has been configured and enabled for auto-start"
      }
      config_disable_acs_service

      节点创建完成后,可登录节点执行 lspci -vvv | grep ACSCtl 确认 PCIe ACS 状态:输出包含 SrcValid- 表示 PCIe ACS 已关闭,SrcValid+ 表示仍处于开启状态,需重新检查脚本是否生效。

      说明

      ecs.ebmgn9g、ecs.ebmgn9gc、ecs.ebmgn9ge 实例的 GPU 之间没有 NVLink、NVSwitch 高速互联,机内卡间通信默认通过 PCIe 进行,效率远低于 NVLink/NVSwitch。因此除了跨节点通过 eRDMA 加速外,还需关闭 PCIe ACS,以提升机内 GPU 与 eRDMA 网卡间的 P2P 通信能力。

步骤三:验证节点 eRDMA 资源

节点池创建完成后,确认节点上的 GPU 和 eRDMA 资源已正确识别并可被调度。

  • 方法一:连接集群,使用 kubectl 连接集群并执行以下命令查看节点的可分配资源。

    kubectl get node <节点名称> -o jsonpath='{.status.allocatable}'

    预期输出如下,表明节点已成功上报 GPU 和 eRDMA 资源:

    {"aliyun/erdma":"400","cpu":"15890m","ephemeral-storage":"243149919035","hugepages-1Gi":"0","hugepages-2Mi":"0","memory":"128290128Ki","nvidia.com/gpu":"1","pods":"64"}
    • "nvidia.com/gpu":"1":表示可用的 GPU 数量为 1。

    • "aliyun/erdma":"400":表示该节点可分配 400 份 eRDMA 资源。

  • 方法二:登录支持 eRDMA 的节点,执行以下命令查看 eRDMA 设备信息。

    ibv_devinfo

    预期输出中显示 erdma_0erdma_1 两个设备且端口状态均为 PORT_ACTIVE,表示 eRDMA 设备已正常启用。

步骤四:(可选)安装 ACK KubeSkoop 组件并配置 eRDMA 监控

如需在训练过程中监控 eRDMA 网卡流量,安装ACK KubeSkoop 组件并接入监控。安装需在提交训练作业前完成,以便采集到完整的流量数据。

  1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,单击组件管理

  2. 组件管理页面,单击网络页签,定位 ACK KubeSkoop 组件,按照页面提示配置组件并完成安装。

  3. 安装完成后,在左侧导航栏选择工作负载 > 容器组,选择命名空间 ack-kubeskoop,查看 Pod 运行状态,确认组件运行正常。然后访问ARMS控制台接入中心功能,搜索 ACK KubeSkoop 网络监控,选定目标集群并完成监控接入。

步骤五:通过 Arena 提交训练作业

使用 Arena 提交 PyTorch 分布式训练作业,并申请 eRDMA 资源加速节点间通信。

  1. 安装云原生AI套件

  2. 配置Arena客户端 并提交训练作业。更多参数,请参见 Arena提交作业核心参数说明

  3. 创建两个分别命名为 mymodelsmyworkspace 的 OSS PVC 实例,分别存放模型,以及训练输出和配置文件。

本文基于 ms-swift 4.2.0 官方镜像并为其添加 eRDMA 支持,镜像构建方法请参见构建生产环境支持 eRDMA 的容器镜像。训练方式为两节点使用 GRPO 对 Qwen/Qwen3.5-35B-A3B 模型进行强化学习微调。

训练过程中如遇问题,请参考常见问题。NCCL 环境变量的完整说明请参见附录

arena submit pytorch \
    --name=pytorch-swift \
    --namespace=default \
    --workers=2 \
    --gpus=8 \
    --share-memory=1000Gi \
    --device=aliyun/erdma=2 \
    --nproc-per-node=8 \
    --env=UCX_TLS=tcp \
    --env=UCX_NET_DEVICES=eth0 \
    --env=NCCL_SOCKET_IFNAME=eth0 \
    --env=NCCL_IB_HCA=erdma_0,erdma_1 \
    --env=NCCL_IB_DISABLE=0 \
    --env=NCCL_IB_GID_INDEX=1 \
    --env=NCCL_NET_GDR_LEVEL=SYS \
    --env=NCCL_P2P_LEVEL=SYS \
    --env=NCCL_GIN_TYPE=0 \
    --env=FLA_TILELANG=0 \
    --env=VLLM_MOE_BACKEND=triton \
    --data=mymodels:/models \
    --data=myworkspace:/workspace \
    --clean-task-policy=None \
    --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/swift:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.20.1-modelscope1.36.3-erdma \
    --image-pull-policy=Always \
    --tensorboard \
    --logdir=/workspace/logs \
    "export NNODES=\$PET_NNODES \
     MASTER_ADDR=\$PET_MASTER_ADDR \
     MASTER_PORT=\$PET_MASTER_PORT \
     NPROC_PER_NODE=\$PET_NPROC_PER_NODE \
     NODE_RANK=\$PET_NODE_RANK && \
     megatron rlhf \
       --rlhf_type grpo \
       --model /models/Qwen/Qwen3.5-35B-A3B \
       --dataset open-r1/DAPO-Math-17k-Processed \
       --tuner_type full \
       --packing true \
       --enable_thinking false \
       --max_length 2048 \
       --global_batch_size 32 \
       --micro_batch_size 1 \
       --num_generations 8 \
       --max_completion_length 512 \
       --tensor_model_parallel_size 4 \
       --expert_tensor_parallel_size 1 \
       --expert_model_parallel_size 8 \
       --sequence_parallel true \
       --optimizer_cpu_offload true \
       --optimizer_offload_fraction 1 \
       --moe_grouped_gemm true \
       --moe_permute_fusion true \
       --reward_funcs accuracy \
       --temperature 0.9 \
       --train_iters 15 \
       --logging_steps 1 \
       --lr 5e-5 \
       --beta 0.04 \
       --epsilon 0.2 \
       --epsilon_high 0.28 \
       --attention_backend flash \
       --recompute_granularity full \
       --recompute_method uniform \
       --recompute_num_layers 1 \
       --dataloader_num_workers 4 \
       --dataloader_pin_memory true \
       --no_save_optim true \
       --no_save_rng true \
       --use_vllm true \
       --vllm_mode colocate \
       --vllm_gpu_memory_utilization 0.3 \
       --vllm_tensor_parallel_size 8 \
       --vllm_enforce_eager true \
       --vllm_max_model_len 2048 \
       --sleep_level 2 \
       --output_dir /workspace/output \
       --tensorboard_dir /workspace/logs"
说明

在 ecs.ebmgn9g、ecs.ebmgn9gc、ecs.ebmgn9ge 实例规格上,NCCL 需要手动指定通信拓扑图文件以保证通信效率。请将拓扑图文件保存到镜像内的绝对路径,并通过 --env=NCCL_GRAPH_FILE=<拓扑图文件绝对路径> 传入。拓扑图文件的获取方式请参见NCCL 环境变量配置

步骤六:验证训练作业与 eRDMA 加速

确认训练作业已成功启动,并验证 eRDMA 网络已生效。

  1. 查看 Master Pod 的日志,日志中显示训练 iteration 信息,说明训练作业正常运行。

    kubectl logs pytorch-swift-worker-0 | head -n 50
  2. 验证 eRDMA 是否生效。在上述 Pod 日志中查找关键信息 Using network IB,如果出现此行,表示节点间通信已通过 eRDMA 加速。

步骤七:(可选)监控 eRDMA 网卡流量

如已在步骤四中安装 KubeSkoop 组件,可实时监控 eRDMA 网卡的网络流量,验证数据传输情况。

  1. 访问 ARMS控制台接入管理功能,在已接入环境中选择目标集群,单击组件管理中的 ACK KubeSkoop 网络监控,可分别查看 Node 和 Pod 级别的监控大盘。

    image.png

性能对比

通过记录训练任务的相关指标和日志,对比开启 eRDMA 前后的训练性能。从下图可得,使用 eRDMA 的训练任务,其迭代时间相比未使用 eRDMA 时最多有超过 28% 的降幅。

说明

为更清晰地对比 eRDMA 开启前后的性能差异,以下两组训练任务在执行前均进行了相同轮次的 warmup。本文性能数据基于特定实验室环境测得,实际性能因模型、规格、数据集与网络状况等因素而异,仅供参考。

image.png

ACK 集群提供 AI Profiling 功能,可从 Torch、Python 和 CUDA Kernel 多个层面分析训练性能,深入定位计算、通信和内存使用上的瓶颈。

清理资源

训练作业完成后,执行以下命令删除作业。此操作将删除作业相关的所有 Pod 和资源,但不会删除 TensorBoard 日志等持久化数据。

arena delete pytorch-swift -n default

预期输出:

INFO[0001] The training job pytorch-swift has been deleted successfully

常见问题

为什么日志中没有显示 NET/IB : Using erdma_0?

可能的原因包括:

  • 未在提交命令中添加 --device=aliyun/erdma=2 参数。

  • 节点不支持 eRDMA,或 eRDMA Controller 组件未正确安装。

  • 容器镜像中缺少 RDMA 用户态库(libibverbs、librdmacm 等)。

解决方法:

  1. 执行 kubectl get node <节点名> -o jsonpath='{.status.allocatable}' 确认节点是否有 aliyun/erdma 资源。

  2. 登录节点执行 ibv_devinfo 检查 eRDMA 设备是否正常。

  3. 检查容器镜像是否包含必要的 RDMA 库。

训练过程中出现 NCCL timeout 错误怎么办?

NCCL timeout 通常由网络不稳定或配置不当引起。建议:

  1. 增加超时时间:设置 --env=NCCL_IB_TIMEOUT=23(默认为 20)。

  2. 增加重试次数:设置 --env=NCCL_IB_RETRY_CNT=10(默认为 7)。

  3. 检查节点间的网络连通性和 eRDMA 设备状态。

训练过程中出现 NCCL Cannot allocate memory 错误怎么办?

NCCL Cannot allocate memory 通常由宿主机 ulimit 配置限制造成。建议:

  1. 检查节点或节点容器运行时的 ulimit 配置,关注 locked memory、open files、stack size 等字段。请注意,该操作会在节点级别全局生效,可能造成内存碎片。

  2. 提升 Pod 的权限级别,并在 Pod 启动参数中自行设置 ulimit 值,可参考如下配置。

    重要

    提升权限操作会引入额外的安全风险,请在完全理解配置后果后谨慎配置。

    apiVersion: v1
    kind: Pod
    metadata:
      name: custom-ulimit
    spec:
      containers:
      - name: configure
        image: <YOUR_TRAINING_IMAGE>
        command:
        - /bin/sh
        - -c
        - |
          ulimit -l unlimited
          echo "Current memlock limit:"
          ulimit -l
          echo "Sleeping..."
          sleep infinity
        securityContext:
          capabilities:
            add: ["SYS_RESOURCE"]

如何判断 eRDMA 是否真正提升了训练性能?

可以通过以下方式对比:

  1. 分别提交使用 eRDMA 和不使用 eRDMA 的训练作业(通过是否添加 --device=aliyun/erdma=2 区分)。

  2. 对比相同训练步数下的完成时间。

  3. 使用 AI Profiling 工具分析通信时间占比。

通常在多节点(2 个以上)、模型参数量较大(数十亿参数以上)的场景下,eRDMA 的性能提升最为明显。

Arena 提交作业失败,提示资源不足怎么办?

可能的原因包括:

  • GPU 或 eRDMA 资源不足。

  • 节点不满足调度条件(如节点选择器、污点容忍)。

解决方法:

  1. 执行 kubectl get nodes 查看节点状态和可用资源。

  2. 执行 kubectl describe pod <Pod名> 查看 Pod 调度失败的详细原因。

  3. 根据提示调整资源请求或增加节点。

附录

Arena 提交作业核心参数说明

参数

说明

建议配置

--name

作业名称,集群内全局唯一

使用具有业务含义的名称

--namespace

作业所属的命名空间

根据团队或项目隔离

--workers

Worker 节点数量(包含 Master)

设置为 2 表示 1 个 Master + 1 个 Worker

--gpus

每个 Worker 使用的 GPU 卡数

根据模型大小和显存需求设置

--device=aliyun/erdma

启用 eRDMA 的关键参数,为每个 Worker 分配 eRDMA 资源

必须设置以启用 eRDMA,ecs.ebmgn9g、ecs.ebmgn9gc、ecs.ebmgn9ge实例规格建议设置为 2

--nproc-per-node

每个节点启动的训练进程数

通常设置为与 --gpus 相同

--clean-task-policy

Pod 清理策略

设置为 None 保留 Pod 以便查看日志

--env

环境变量

用于配置 NCCL 通信参数

NCCL 环境变量配置

在使用 ecs.ebmgn9g、ecs.ebmgn9gc、ecs.ebmgn9ge实例规格时,针对完整使用整机 8 卡 GPU 和 2 张 eRDMA 网卡的固定通信场景,可使用预设的 NCCL 通信拓扑信息,加快 NCCL 通信初始化过程,避免 NCCL 2.30 及之前版本拓扑探测不准确带来的通信效率问题。通过 NCCL_GRAPH_FILE 环境变量指向拓扑图 XML 文件的绝对路径来使用。请在充分了解 NCCL 通信过程后,结合具体通信场景谨慎使用。

环境变量

说明

推荐配置

NCCL_IB_DISABLE

控制是否禁用 IB/RoCE

eRDMA 场景下设置为 0,排查测试时可设置为 1

NCCL_SOCKET_IFNAME

指定用于通信的网卡接口

设置为 eth0(ACK 集群默认网卡)

NCCL_NET_GDR_LEVEL

GPU 与 NIC 间的最大拓扑距离,不超过设定值时使用 GPU Direct RDMA(LOC、PIX、PXB、PHB、SYS,分别对应 0-4)

eRDMA 场景下推荐设置为 SYS

NCCL_P2P_LEVEL

GPU 间的最大拓扑距离,不超出设定值时使用点对点通信(LOC: 0、NVL、PIX: 1、PXB: 2、PHB: 3、SYS: 4)

eRDMA 场景下推荐设置为 SYS,在本机内始终使用 P2P

NCCL_ALGO

集合通信算法

可选 RingTree 等,根据网络拓扑选择

NCCL_DEBUG

日志级别

调试时设置为 INFO,生产环境可改为 WARN

NCCL_IB_HCA

指定使用的 RDMA 网卡

通过 ibstat 查看可用网卡名称

NCCL_IB_TIMEOUT

IB 通信超时时间

根据网络延迟调整

NCCL_IB_RETRY_CNT

IB 通信失败重试次数

不稳定网络可适当增加

NCCL_SHM_DISABLE

当 P2P 禁用时,控制是否禁用共享内存。禁用则回退到 Socket 通信

根据具体环境按需调整

NCCL_GRAPH_FILE

指定 NCCL 通信拓扑文件的绝对路径

根据具体硬件拓扑而定。仅 ecs.ebmgn9g、ecs.ebmgn9gc、ecs.ebmgn9ge 实例规格需使用示例文件

更多 NCCL 环境变量说明,请参见 NCCL 官方文档

参考 Dockerfile

以下 Dockerfile 在 ms-swift 官方镜像基础上安装了 eRDMA 用户态库,可作为自定义训练镜像的参考。

FROM modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.20.1-modelscope1.36.3-swift4.2.0

RUN wget -qO - https://mirrors.aliyun.com/erdma/GPGKEY | apt-key add - && echo "deb [ arch=amd64 ] https://mirrors.aliyun.com/erdma/apt/ubuntu jammy/erdma main" | tee /etc/apt/sources.list.d/erdma.list && apt update && apt install -y libibverbs1 ibverbs-providers ibverbs-utils librdmacm1

使用 ms-swift 对 Qwen3-4B-Instruct-2507 进行 LoRA 微调

以下示例使用单卡两节点对 Qwen3-4B-Instruct-2507 进行 LoRA 微调,可作为入门验证场景。

arena submit pytorch \
    --name=pytorch-swift \
    --namespace=default \
    --workers=2 \
    --gpus=1 \
    --nproc-per-node=1 \
    --device=aliyun/erdma=1 \
    --env=UCX_TLS=tcp \
    --env=UCX_NET_DEVICES=eth0 \
    --env=NCCL_SOCKET_IFNAME=eth0 \
    --env=NCCL_IB_HCA=erdma_0,erdma_1 \
    --env=NCCL_IB_DISABLE=0 \
    --env=NCCL_IB_GID_INDEX=1 \
    --env=NCCL_NET_GDR_LEVEL=SYS \
    --env=NCCL_P2P_LEVEL=SYS \
    --env=NCCL_GIN_TYPE=0 \
    --clean-task-policy=None \
    --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/swift:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.20.1-modelscope1.36.3-erdma \
    --image-pull-policy=Always \
    --data=mymodels:/models \
    --data=myworkspace:/workspace \
    --tensorboard \
    --logdir=/workspace/logs \
    "torchrun \
      --master_port \${PET_MASTER_PORT} \
      --nproc_per_node=\${PET_NPROC_PER_NODE} \
      --nnodes=\${PET_NNODES} \
      --node_rank=\${PET_NODE_RANK} \
      --master_addr=\${PET_MASTER_ADDR} \
      sft.py \
      --model /models/Qwen/Qwen3-4B-Instruct-2507 \
      --tuner_type lora \
      --dataset 'swift/self-cognition#1000' \
      --num_train_epochs 1 \
      --lora_rank 8 \
      --lora_alpha 32 \
      --learning_rate 1e-4 \
      --gradient_accumulation_steps \$(( 32 / \$PET_NPROC_PER_NODE / \$PET_NNODES )) \
      --eval_steps 100 \
      --save_steps 100 \
      --save_total_limit 2 \
      --logging_steps 5 \
      --model_author swift \
      --model_name swift-robot"