ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

NCCL 网络故障排查实战:从接口选择、端口管理到 InfiniBand 与 RoCE 网络诊断

NCCL 网络故障排查实战:从接口选择、端口管理到 InfiniBand 与 RoCE 网络诊断
  • 高性能计算
  • 通信
  • 深度学习
  • 分布式训练

【免费下载链接】nccl

Optimized primitives for collective multi-GPU communication

项目地址:https://gitcode.com/gh_mirrors/nc/nccl
点击查看免费下载

本篇技术指南围绕 NCCL 跨节点通信的网络故障排查展开,覆盖三大主题:如何正确指定 NCCL 使用的 IP 网络接口与 TCP 端口范围、如何用 perftest/RDMA 工具集对 NIC 进行带宽与延迟基线诊断、以及 InfiniBand 与 RoCE 两类组网下各自的专项检查方法(Subnet Manager、端口错误计数、连通性测试与 GPUDirect RDMA 相关问题)。读完本文,读者可以掌握一套可复制的跨节点通信排障流程,并能结合当前仓库源码理解 NCCL 报错(如ibv_reg_mr failed、ibv_modify_qp failed)背后的实现机制。以下内容基于 网络故障排查文档 整理,并结合仓库源码做了实现层面的印证与扩充。

一、IP 网络接口:NCCL 的自动检测与手动指定

NCCL 会自动检测用于跨节点通信的网络接口。风险在于:某些接口处于 UP 状态但节点之间实际无法通信,NCCL 仍可能尝试使用它们,结果就是在ncclCommInitRank等初始化函数中直接报错,甚至挂死(hang)。因此排障的第一步就是确认接口选择是否符合预期。

用 NCCL_SOCKET_IFNAME 显式指定接口

解决方案是设置NCCL_SOCKET_IFNAME环境变量。该变量接受接口前缀列表,语法要点(详见 环境变量手册):

  • 多个前缀用逗号分隔,如eth会匹配eth0、eth1等所有以eth开头的接口;
  • 用=前缀做精确匹配:=eth0只使用eth0,=eth0,eth1只使用这两个接口;
  • 用^前缀做排除:^docker表示不使用任何以docker开头的接口,^=docker0表示只排除docker0。

自动选择算法的行为值得注意:默认情况下,回环接口lo与 docker 接口docker*只有在没有其他可用接口时才会被选中;默认算法会优先选择以ib开头的接口;而一旦显式设置了NCCL_SOCKET_IFNAME,就会绕过自动选择算法,直接使用所有匹配手动选择的接口。

源码印证:接口发现逻辑

从源码结构看,这一逻辑位于 src/misc/socket.cc 的ncclFindInterfaces函数中:

  • 优先读取NCCL_SOCKET_IFNAME,若设置了则直接交给ncclOsFindInterfaces按用户规则过滤;
  • 未设置时先尝试匹配ib前缀的接口(与文档描述的"优先 ib 接口"一致);
  • 都不行时依次回退到^docker,lo,virbr(排除 docker、lo、virbr 后取其余接口)、docker、lo、virbr。

这段回退链正好解释了文档所说的故障场景:当节点上存在 UP 但不可达的接口时,自动算法可能选中它们,最终导致初始化失败或挂起。排障时应先用ip link之类的命令确认接口真实可用,再用NCCL_SOCKET_IFNAME锁定正确的接口。

二、TCP 端口范围管理

NCCL 会打开 TCP 端口用于进程互联和交换连接信息(bootstrap 阶段)。如果环境有端口限制(防火墙、安全组等),可以通过 Linux 内核的net.ipv4.ip_local_port_range属性把 NCCL 使用的端口收敛到一个可管理的范围。

把 NCCL 端口限制在50000-51000:

echo 50000 51000 > /proc/sys/net/ipv4/ip_local_port_range

如需持久化,写入/etc/sysctl.conf:

echo "net.ipv4.ip_local_port_range = 50000 51000" >> /etc/sysctl.conf

收敛端口范围的实际价值在于可以按范围开放防火墙规则。例如在 Google Cloud 上为打了ncclnet标签的机器开放 NCCL 端口、SSH 以及 gVNIC 的 1024-1039 端口:

gcloud compute --project=myproject firewall-rules create ncclnet-ingress \ --direction=INGRESS --priority=1 --network=ncclnet --action=ALLOW \ --rules=tcp:50000-51000,22,1024-1039 --destination-ranges=0.0.0.0/0 --target-tags=ncclnet

适用前提:该示例针对 Google Cloud 的防火墙规则语法;其他云平台或自管防火墙需要用各自的方式放行相同端口范围。核心原则不变——先收敛端口范围,再按范围开墙。

三、NIC 级诊断:在跑 NCCL 之前先测链路

在 InfiniBand(或 RoCE)上运行 NCCL 之前,先做底层网络测试确认端口是 UP 的、且工作在预期配置(link layer、link rate、active 状态)下,可以省掉大量"NCCL 挂了但其实是网络问题"的误判。

3.1 端口健康快速检查:ibstatus 与 ibstat

# 按端口汇总视图 ibstatus # 按 HCA 和端口详细视图 ibstat

健康端口的特征:

  • 端口状态为Active(而不是Down、Init或Armed);
  • 物理状态显示链路已 up(通常是LinkUp);
  • link layer 符合预期(例如 RoCE 环境应为Ethernet,纯 IB 环境为InfiniBand),且所有参与传输的 NIC 之间保持一致;
  • 报告的Rate与预期组网速率一致,没有意外的降速(downshift)。

3.2 带宽测试:ib_write_bw

端口状态正常后,选两台计算节点分别作为 server 和 client 测试点对点带宽:

# server 节点 ib_write_bw -d <device> -a # client 节点 ib_write_bw -d <device> <server_hostname_or_ip> -a

其中<device>替换为ibstat中显示的 HCA 设备名(例如mlx5_0),-a表示遍历所有消息大小。

GPUDirect RDMA 专项对比:排查 GPUDirect RDMA 时,建议把 host 内存结果与 GPU 内存结果做对比,以定位问题出在 PCIe/驱动路径还是纯 NIC 路径。依赖perftest的构建方式,GPU 内存选项可能包括:

# GPU 内存路径 ib_write_bw -d mlx5_0 --use_cuda=<gpu_id> <server_hostname_or_ip> -a # DMA-BUF 路径(需要内核、驱动和 perftest 构建均支持) ib_write_bw -d mlx5_0 --use_cuda=<gpu_id> --use_cuda_dmabuf <server_hostname_or_ip> -a

GB300 之类的平台上,某些perftest构建还暴露额外的数据直通模式。对比结果前,先用ib_write_bw --help确认当前构建实际支持的 GPU 内存选项。

从源码结构看,NCCL 的 IB 传输同时探测这两种 GPUDirect 路径:src/transport/net_ib/gdr.cc 中的ncclIbDmaBufSupport通过一次性探测确认内核 DMA-BUF 是否可用(dmaBufSupported == 1表示可用),并与ncclIbGdrSupport()(传统 nvidia-peermem 路径)一起在 src/transport/net_ib/connect.cc 决定 flush 等优化是否启用。所以--use_cuda与--use_cuda_dmabuf的对比结果,直接对应 NCCL 运行时可能走的两条 DMA 路径。

3.3 延迟测试:ib_write_lat

带宽健康不代表尾延迟健康。如果问题表现为卡顿、长尾或间歇性变慢,还要测点对点延迟:

# server 节点 ib_write_lat -d <device> # client 节点 ib_write_lat -d <device> <server_hostname_or_ip>

延迟偏高或不稳定,尤其伴随带宽波动时,通常指向拥塞、重传或链路退化。

3.4 RDMA 协议层统计:rdma statistic

rdma statistic可以在 RDMA 层识别重传或类似丢包的症状:

rdma statistic

重点观察测试运行期间这些计数器是否增长:

  • rnr_nak_retry_err(接收未就绪引发的重传错误)
  • packet_seq_err(报文序号错误)
  • implied_nak_seq_err(隐含 NAK 序号错误)
  • local_ack_timeout_err(本地 ACK 超时)

非零或持续增长的值通常意味着丢包、重试或其他传输层问题。

3.5 链路健康:mlxlink

如果问题看起来像 PCIe、C2C 或物理端口健康度退化,直接用mlxlink查链路:

mlxlink -d <mst_device>

用它确认预期的链路宽度(width)、链路速率、错误状态和端口整体健康度。当带宽或延迟退化而软件配置看不出问题时,这一工具特别有用。

四、InfiniBand 网络专项排查

4.1 Subnet Manager 状态检查

InfiniBand 组网必须有 Subnet Manager(SM)在运行。用如下命令检查:

sudo sminfo

如果sminfo失败或显示没有 SM,确保至少在某个节点上运行了 SM(例如opensm服务)。没有 SM 的 IB 网络无法路由,这是"整网不通"类故障的第一检查项。

4.2 端口错误计数器:perfquery

用perfquery检查链路错误、符号错误或丢包,这类计数通常指向线缆或交换机问题:

sudo perfquery -x <lid>

关注错误计数器,尤其是SymbolErrorCounter、LinkErrorRecoveryCounter、LinkDownedCounter的非零值——它们可能指示硬件或布线问题。

4.3 连通性测试:ibping

ibstat/ibstatus看不出问题但仍怀疑连通性时,用ibping测试节点间连通性。ibping需要先在对端节点启动 server:

# 在远端节点启动 ibping server sudo ibping -S # 在本节点用 LID ping 该 server(LID 见 ibstat 输出) sudo ibping <lid from ibstat>

4.4 全Fabric 综合诊断:ibdiagnet

更彻底的 Fabric 级诊断(通常需要 SM 访问权限):

sudo ibdiagnet

它检查拓扑、路由,并报告整个 Fabric 中的错误。一个典型的排障场景:NCCL 在大部分 rail 上正常,但反复在某一条 rail 上失败或变慢——先跑ibdiagnet,检查报告里连接该 rail 的交换机端口是否存在缺链、坏端口或路由不一致,处理后再重试 NCCL 任务。

4.5 NCCL 报错:ibv_create_qp / ibv_reg_mr 失败与 memlock 限制

InfiniBand 上一个常见问题是库无法注册足够的 pinned memory,典型报错为:

NCCL WARN Call to ibv_create_qp failed

或:

NCCL WARN Call to ibv_reg_mr failed

解决方案是去掉用户注册 pinned memory 的限额。在/etc/security/limits.conf(或发行版等价配置)中加入:

* soft memlock unlimited * hard memlock unlimited

注意:修改limits.conf通常要求用户重新登录、重启,或者在 Slurm 集群上确保作业以新限制启动。用ulimit -l验证新的限制值是否生效。

这些报错并非凭空而来:在 src/misc/ibvwrap.cc 中,NCCL 对所有 verbs 调用做了统一封装——wrap_ibv_reg_mr(第 193 行)、wrap_ibv_create_qp(第 253 行)等函数通过IBV_PTR_CHECK_ERRNO宏检查返回值,失败时打印带函数名的 WARN 并向上返回ncclSystemError。也就是说,你在日志里看到的每一条Call to ibv_xxx failed都来自这一层包装,对应的失败点可以在 src/transport/net_ib/connect.cc 的连接建立路径(如wrap_ibv_create_qp调用点、QP 状态迁移调用点)中定位。

五、RoCE(RDMA over Converged Ethernet)网络专项排查

RoCE 组网与 InfiniBand 的诊断工具链不同,需要针对以太网信道做检查。

5.1 端口计数器:ethtool

ethtool -S <nic_name>

检查错误、丢包、pause 帧、PFC 相关计数器。这些计数器的非零值可能指示硬件问题、布线问题或无损网络(lossless fabric)配置不当。

5.2 拥塞指标

RoCE 性能问题通常与拥塞控制或无损组网配置相关,而不是链路直接故障。除ethtool外,还应检查环境中交换机和 NIC 暴露的 PFC、ECN、CNP、队列丢包计数器。如果这些计数器在延迟长尾变长或吞吐不稳定期间持续增长,应先排查拥塞控制与无损组网配置,再考虑调整 NCCL 侧的参数。

5.3 连通性测试:rping

端口级检查无异常但仍怀疑连通性问题时,用rping测试。同样需要先在对端节点启动 server:

# 在远端节点启动 rping server rping -s -a <ip_address_of_the_server_nic> -V -C 10 # 在本节点用 IP ping 该 server rping -c -a <ip_address_of_the_server_nic> -S <ip_address_of_the_client_nic> -V -C 10

参数含义:-s/-c分别为 server/client 模式,-a指定本地地址,-S指定对端地址,-V开启详细输出,-C 10表示执行 10 个连接循环。

5.4 NCCL 报错:ibv_modify_qp EINVAL 与 GID index

RoCE 上一个常见问题是 RoCE v2 NIC 选错了 GID index,典型报错:

NCCL WARN Call to ibv_modify_qp failed with error Invalid argument

版本差异是排障关键:

  • NCCL 2.21 及以后:GID index 由 NCCL 动态选择,用户不应再设置NCCL_IB_GID_INDEX;
  • 更早版本:需要手动运行show_gids查看 GID 表,然后把NCCL_IB_GID_INDEX设为 RoCE v2 GID 对应的索引。

此外,RoCE 组网可能还需要设置NCCL_IB_TC(InfiniBand 流量类字段),具体取值需参照网卡/交换机厂商文档。

源码印证:动态 GID 选择与报错提示机制

当前仓库中的实现与上述版本行为完全一致:

  • 参数定义在 src/transport/net_ib/connect.cc:NCCL_PARAM(IbGidIndex, "IB_GID_INDEX", -1),默认值-1即"交给 NCCL 动态选择";
  • 动态选择逻辑在ncclIbGetGidIndex(src/transport/net_ib/connect.cc#L298-L335):IB 链路层优先选取携带可路由 FLID 的 GID;RoCE 链路层下,若用户显式设置了NCCL_IB_GID_INDEX(≥0)则直接采用,否则按地址族(NCCL_IB_ADDR_FAMILY,默认AF_INET)、地址范围(NCCL_IB_ADDR_RANGE)和 RoCE 版本(NCCL_IB_ROCE_VERSION_NUM,默认 2)扫描 GID 表,通过/sys/class/infiniband/<dev>/ports/<port>/gid_attrs/types/<idx>读取每个 GID 的 RoCE 版本属性来挑选最匹配的条目。这些配套变量自 2.21 引入,可在 环境变量手册 中查看完整取值说明;
  • 报错提示在 src/misc/ibvwrap.cc:wrap_ibv_modify_qp对ibv_modify_qp带重试(按NCCL_IB_MQP_RETRY_CNT次数递增睡眠重试),最终失败才打印Call to ibv_modify_qp failed with %d %s,并调用printIbModifyQpHint输出针对性提示——当 errno 为EINVAL时明确提示"很可能是NCCL_IB_GID_INDEX强制了错误的 GID index,可设置NCCL_IB_GID_INDEX=-1启用自动检测",errno 为ETIMEDOUT时则提示检查 NIC 是否跨 rail 连接(可用NCCL_CROSS_NIC=0验证)。

因此当你看到ibv_modify_qp failed with ... Invalid argument时,日志里通常会同时附带上述 HINT 行,直接按提示处理即可,不必再手动猜测。

六、结合 NCCL 日志验证排查结论

网络诊断工具给出的结论,最终要回到 NCCL 自身的日志中交叉验证。NCCL 提供分级日志(NCCL_DEBUG=VERSION/WARN/INFO/TRACE),可用NCCL_DEBUG_SUBSYS过滤子系统(网络相关日志属于NET/IB子系统)、NCCL_DEBUG_FILE按主机和 PID 分流落盘,详见 日志文档。排障时建议:

  1. 用NCCL_DEBUG=INFO NCCL_DEBUG_SUBSYS=NET,ENV启动作业,确认 NCCL 实际选择了哪些网络接口和 IB HCA(对应前文NCCL_SOCKET_IFNAME、NCCL_IB_HCA的解析结果,接口选择日志即来自 src/misc/socket.cc 中的INFO(NCCL_ENV, ...)输出);
  2. 与ibstat/ethtool/rdma statistic的测量结果互相印证,区分"NCCL 配置问题"与"网络本身问题"。

小结

NCCL 网络排障可以归纳为一条从上层到下层、再到组网类型的检查链:

层次关键手段常见问题
接口选择NCCL_SOCKET_IFNAME显式指定选中 UP 但不可达的接口导致 init 失败/挂起
端口管理ip_local_port_range+ 防火墙按范围放行bootstrap TCP 连接被防火墙拦截
NIC 基线ibstatus/ibstat、ib_write_bw、ib_write_lat、rdma statistic、mlxlink降速、重传、尾延迟、PCIe/端口退化
InfiniBandsminfo、perfquery、ibping、ibdiagnet;memlock 限额无 SM、符号错误、rail 级路由问题、ibv_reg_mr失败
RoCEethtool -S、PFC/ECN/CNP 计数、rping;GID index 动态选择拥塞/无损配置不当、ibv_modify_qpEINVAL

核心原则:先用底层工具确认网络本身健康,再看 NCCL 报错与 HINT,最后才调整 NCCL 环境变量;对 NCCL 2.21 以后的版本,让 GID 选择交给自动检测(不要设置NCCL_IB_GID_INDEX),是 RoCE 排障的第一步。

  • 高性能计算
  • 通信
  • 深度学习
  • 分布式训练

【免费下载链接】nccl

Optimized primitives for collective multi-GPU communication

项目地址:https://gitcode.com/gh_mirrors/nc/nccl
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进