适用场景:GPU 训练集群、RoCEv2 组网、NCCL AllReduce 跑不满、交换机侧 PFC/ECN 联调
排障链路:NCCL 参数 → 网卡 hw_counters → ib_write_bw 打流 → 华三交换机 QoS
核心认知:RoCE 问题从来不是单一层面能定位的,主机侧打标不对、交换机 PFC 不开、GID index 选错,任何一个都能让带宽腰斩
一、背景:为什么 RoCE 排障最容易被低估
AI 集群交付里,最容易被误判成"NCCL 不行"或"网卡坏了"的,其实是 RoCE 链路没调对。表现通常是:
- 训练启动卡在 bootstrap,或 AllReduce 带宽只有理论值 30%~50%
ib_write_bw单向通、反向不通- GPU 利用率周期性掉,伴随网卡
np_cnp_sent疯涨 - 交换机端口 PFC 帧暴增,但服务器侧看起来一切正常
RoCEv2 跑在 UDP/IP 上,依赖无损网络 + 正确打标 + GID 选对三者同时成立。任何一层错位,现象都长一个样------慢。
二、主机侧:NCCL 参数怎么配
下面是一版在 Mellanox/NVIDIA 网卡 + RoCEv2 环境下跑通过的启动脚本框架。注意:HCA 名、GID index、网卡名必须按你机器现场核对,不能直接抄。
bash
# 走 RDMA,不要禁掉
export NCCL_IB_DISABLE=0
# GPUDirect RDMA 距离门限(2=跨 PCIe switch 可用,具体按拓扑测)
export NCCL_NET_GDR_LEVEL=2
# RoCEv2 走 GID index 3(常见,但必须用 show_gids 确认)
export NCCL_IB_GID_INDEX=3
# Traffic Class:NCCL_IB_TC 不是裸 DSCP 值,
#它是把 DSCP 放高 6 位、ECN 放低 2 位打包出来的 traffic_class 字节
export NCCL_IB_TC=106
# 建连阶段走 TCP bootstrap 的网卡
export NCCL_SOCKET_IFNAME=bond0,bond1,eth0
#明确绑定用哪些 HCA,避免 NCCL 选到管理网网卡
export NCCL_IB_HCA=mlx5_bond_1,mlx5_bond_2,mlx5_bond_3,mlx5_bond_4
#超时与重试(大集群、长链路建议调大)
export NCCL_IB_TIMEOUT=22
export NCCL_TIMEOUT=180
自适应脚本思路(生产推荐)
别写死 HCA 列表。训练脚本里先探测:
bash
for hca in mlx5_bond_1 mlx5_bond_2 mlx5_bond_3 mlx5_bond_4; do
if [ -d "/sys/class/infiniband/$hca" ]; then
HCA_LIST="HCA_LIST,hca"
fi
done
export NCCL_IB_HCA=${HCA_LIST#,}
再判断是否存在 /sys/class/infiniband/mlx5_bond_4 或 /sys/class/net/bond0,区分"特殊节点"和"标准 worker",给不同的 HCA 顺序。
GID index 必须现场查
看每个 GID 槽位对应什么类型
bash
for f in /sys/class/infiniband/mlx5_0/ports/1/gids/*; do
idx=${f##*/}
echo "idx=$idx gid=$(cat $f) type=$(cat /sys/class/infiniband/mlx5_0/ports/1/gid_attrs/types/$idx 2>/dev/null)"
done
挑 type 是 RoCE v2 且 GID 末尾是你网卡 IPv4 地址 的那一行,把 idx 填到 NCCL_IB_GID_INDEX。别默认就是 3,不同驱动/固件/网卡半卡可能不一样。
三、RDMA 硬件计数器:RoCE 排障的硬功夫
NCCL 报错是结果,网卡计数器才是原因。路径在:
bash
/sys/class/infiniband/mlx5_XX(填实际的)/ports/1/hw_counters/(这里下下面列表里的计数器的名字)
重点盯这几个
| 计数器 | 含义 | 异常说明 |
|---|---|---|
out_of_sequence |
报文乱序到达 | LAG 哈希不均、多路径、自适应路由没开导致乱序 |
local_ack_timeout_err |
本端 ACK 超时 | 对端没回、链路丢包、buffer 被打满 |
np_cnp_sent |
本端发了拥塞通知包 | 非零正常,说明 DCQCN 在干活;持续暴涨=真拥塞 |
rp_cnp_handled |
本端收到并处理了 CNP | 说明对端在通知你降速,DCQCN 闭环正常 |
rnr_nak_retry_err |
接收端没准备好被重试 | 对端 CQ/QP 资源不够,或接收端 CPU 没跟上 |
np_ecn_marked_roce_packets |
本端发出的 RoCE 包被打 ECN | 交换机在标记拥塞,非零正常,但斜率太陡要查阈值 |
packet_seq_err |
序列号错误 | 疑似丢包或重传异常 |
排障套路
测前清基线(记录当前值)
bash
for c in out_of_sequence local_ack_timeout_err np_cnp_sent rp_cnp_handled np_ecn_marked_roce_packets rnr_nak_retry_err; do
echo "c = (cat /sys/class/infiniband/mlx5_0/ports/1/hw_counters/$c)"
done
跑一轮 AllReduce 或 ib_write_bw
再读一次,看 delta
判断逻辑:
out_of_sequence涨得快 → bond 哈希策略不对(没开 layer3+4),或需要开自适应路由np_cnp_sent和rp_cnp_handled都很高 → 网络在拥塞,去查交换机 ECN 阈值是不是太激进了local_ack_timeout_err涨 → 对端可能 PFC 被暂停太久,或光模块/线缆有问题rnr_nak_retry_err涨 → 接收端 buffer 小,调大NCCL_BUFFSIZE或接收端队列深度
四、ib_write_bw 打流:先证明物理链路是好的
NCCL 跑不满,先别怪 NCCL。用 perftest 里的 ib_write_bw 单独压网卡。
服务端(接收端)
bash
ib_write_bw -d mlx5_0 -x 3 -F -R -T 136 --port 11001 -s 65536 --report_gbits -q 200 --run_infinitely
客户端(发送端)
bash
ib_write_bw -d mlx5_0 -x 3 -F -R -T 136 --port 11001 -s 65536 --report_gbits -q 200 <服务端IP>
参数速查
| 参数 | 作用 |
|---|---|
-d mlx5_0 |
指定 RDMA 设备 |
-x 3 |
GID index,RoCE 必须指定,值来自 show_gids |
-F |
忽略 CPU 频率告警 |
-R |
用 rdma_cm 建连 |
-T 136 |
ToS 字节(对应 DSCP 打标) |
--tclass=236 |
等价写法,打 Traffic Class |
-s 65536 |
单消息 64 KB,压带宽常用 |
-q 200 |
QP 数量,单 QP 打不满 200G/400G 网卡 |
--report_gbits |
以 Gbit/s 输出 |
-D 10 |
跑 10 秒 |
--run_infinitely |
常驻,配合监控脚本读计数器 |
验收基线(经验值)
- 200G 网卡:单端口应跑到 180+ Gbps
- 400G 网卡:单端口应跑到 370+ Gbps
- 单向通、反向报
Failed status 4→ 八成是对端 PCIe/NIC 拓扑或 GID 不对,不是交换机问题。
⚠️ 打流时一定双向都测 。A→B 通 B→A 不通,优先查 B 这块网卡的
ibstat状态、NUMA 亲和、PCIe 带宽。
五、bond 与网卡侧基础调优
5.1 bond 配置(RoCE 推荐 mode=4 + layer3+4)
bash
BONDING_OPTS="miimon=100 mode=4 xmit_hash_policy=layer3+4"
为什么必须 layer3+4:RDMA 点对点通信时 IP 和 MAC 不变,只用 L2/L3 哈希,所有流会砸到同一条成员口上。源端口有随机性,layer3+4 才能把多 QP 流量摊开。
5.2 RX ring 调整
当前值小于预设再调,别无脑调。
bash
RX_MAX=4096
for DEVICE in ens4f0 ens4f1 ens5f0 ens5f1 ens7f0 ens7f1; do
cur=(ethtool -g DEVICE | awk '/RX:/&&2!="RX:"{print 2; exit}')
if [ "{cur:-0}" -lt "RX_MAX" ]; then
ethtool -G DEVICE rx RX_MAX
fi
done
5.3 MTU 统一
RoCE 链路 MTU 必须端到端一致(网卡、ToR、Spine 全统一),否则分片开销直接吃掉带宽:
bash
ip link set bond0 mtu 1500 # 保守值
或 jumbo:ip link set bond0 mtu 9216 (整链都得改)
5.4 路由与抓包辅助
添加静态路由到训练网
bash
route add -net 10.223.128.0/20 gw 10.223.159.254 dev bond1
抓 ARP / RoCE 报文
bash
tcpdump -i ens5f0 -w 2.pcap -c 100 arp
tcpdump -i bond0 -nn udp port 4791 -c 100
六、华三交换机侧:只给框架,不写死阈值
服务器打标再漂亮,交换机不配合一样白搭。华三 Comware 上的核心动作就三条:
6.1 信任模式要对
bash
interface HundredGigE1/0/1
qos trust dscp
priority-flow-control enable
6.2 只在 RoCE 数据优先级开 no-drop
假设 RoCE 走 priority 3,就只开 3。
bash
priority-flow-control no-drop dot1p 3
别把 0~7 全开。PFC 是"按优先级暂停整类流量",开多了容易 PFC 风暴、死锁,还会把管理/IRF/存储流量一起暂停。
6.3 ECN 阈值要现场调
思路:min-threshold 别太低,max-threshold 给足,probability 按机型文档来。
bash
qos ecn profile roce-profile
ecn mode wred
ecn queue 3 min-threshold 200 max-threshold 800
ecn queue 3 probability 100
经验起点(不是万能值):每端口 buffer 32 MB 时,ECN min 设 3~4 MB,max 设 12~16 MB,PFC 触发放 24 MB 以上,再拿真实训练流量微调。
6.4 端到端一致性检查清单
- 服务器 DSCP 值 ↔ 交换机 dscp-to-8021p 映射 ↔ PFC 优先级 三处一致
- CNP 所在优先级不能开 no-drop,否则 CNP 自己被暂停,DCQCN 闭环断掉
- MTU、ToS、GID 类型(RoCEv2)全链路对齐
七、踩坑清单
| 现象 | 先查什么 |
|---|---|
| NCCL 启动卡很久 | NCCL_SOCKET_IFNAME 绑错网卡,bootstrap 走管理网 |
| AllReduce 只有 30% 带宽 | GID index 不对 / 没走 RoCEv2 / 没开 GDR |
| 单向通反向不通 | 对端 GID、NUMA、PCIe 拓扑;ibstat 看 State 是否 Active |
out_of_sequence 暴涨 |
bond 没开 layer3+4,或需要开自适应路由 |
np_cnp_sent 持续高 |
交换机 ECN 阈值太激进,DCQCN 一直在降速 |
| 交换机 PFC 帧暴增 | RoCE 优先级没隔离,或 buffer 水线太低 |
local_ack_timeout_err 涨 |
对端被 PFC 暂停太久 / 光模块或线缆问题 |
| 改完重启失效 | mlnx_qos / PFC / 路由没写持久化,进 systemd service 或 rc.local |
| 多节点表现不一致 | 固件版本不一致,或网卡命名乱序导致 HCA 绑错 |
八、小结
RoCE 排障的四层闭环:
- NCCL 层 :HCA 绑对、
NCCL_IB_GID_INDEX用 show_gids 确认、NCCL_IB_TC打标和交换机队列对齐 - 网卡计数器层 :
out_of_sequence/np_cnp_sent/rp_cnp_handled/np_ecn_marked_roce_packets看 delta,比看 NCCL 日志更早发现问题 - 打流层 :
ib_write_bw -x 3 -q 200双向都跑,先证明物理链路到线速 - 交换机层:只给 RoCE 优先级开 PFC no-drop,ECN 阈值现场调,端到端 DSCP 映射一致
一句话:RoCE 不是"配完就能跑",是"配完要能解释每一个计数器为什么这样跳"才算交差。
有问题的在评论区贴 ibstat + show_gids + hw_counters delta,我看到会回。