# NCCL 问题排查
## NCCL 建联失败(Bootstrap / Connect Fail)
### 1.1 典型现象
- `ncclSystemError` / `ncclInvalidUsage` / `ncclRemoteError`
- 日志关键字:`bootstrap`、`connect failed`、`unhandled cuda error`、`Call to ibv_...`
- 作业在 `ncclCommInitRank` / `ncclCommInitRankConfig` 阶段退出,训练 step 0 未开始
- 部分 rank 卡在 `waiting for all peers to connect`
### 1.2 快速定位 checklist
| 顺序 | 检查项 | 命令 / 方法 |
|---|---|---|
| 1 | NIC 状态 | `ibstatus` / `ibv_devinfo` / `ethtool` / `mlxlink` |
| 2 | GID / 路由可达 | `show_gids` + `ib_send_lat` 端到端 |
| 3 | RDMA CM 端口 | `ss -ltnp \| grep 4791` (RoCEv2 默认)、防火墙 |
| 4 | GPU 拓扑 | `nvidia-smi topo -m`、确认 `PXB/PIX/NODE/SYS` |
| 5 | NCCL 环境 | `NCCL_DEBUG=INFO`、`NCCL_IB_HCA`、`NCCL_SOCKET_IFNAME`、`NCCL_NET_GDR_LEVEL` |
| 6 | PCIe ACS | `lspci -vvv \| grep ACSCtl` — SrcValid/TransBlk 应为 `-` |
### 1.3 根因层级
1. **硬件层**:NIC link down、光模块劣化(误码率高)、PCIe 训练速率跌档(`lspci -vv` LnkSta)
2. **拓扑层**:GPU 与 NIC 不同 NUMA / 不同 Root Complex、ACS 未关闭导致 GDR 不通
3. **协议层**:QP 状态机卡在 `INIT/RTR`、PSN 不匹配、MTU 不一致(4200 vs 4096 vs 1500)
4. **网络层**:ToR / Spine 路由黑洞、ECMP hash 冲突打到慢路径、BGP 失联
5. **软件层**:NCCL / driver / OFED / CUDA 版本组合未验证;`libnccl-net.so` 插件路径错误
6. **调度层**:Pod 绑核错误,NIC 亲和性未下发
### 1.4 处置动作
- 立即:剔除异常节点 → drain → 让 K8s / 调度器重新拉起
- 5 分钟内:在保留现场前打包 `dmesg / ibdump / nccl-test` 日志
- 30 分钟:通过 `nccl-tests` (`all_reduce_perf -b 8 -e 128M -g 8`) 二分定位坏节点对
---
## AllReduce / AllToAll 慢(Perf Degradation)
### 2.1 典型现象
- 单 step 训练时间突增 2~10×,但作业未挂
- `nccl-tests` 带宽未达理论值(200G 网口应达 ~24GB/s 单向)
- 慢主要出现在跨机 ring/tree 段;单机内 NVLink 正常
- Prometheus: `rdma_tx_bytes` 抖动、`ecn_marked_packets` 上升
### 2.2 快速定位 checklist
| 维度 | 工具 | 关注指标 |
|---|---|---|
| GPU 侧 | `nvidia-smi dmon`、Nsight Systems | SM 利用率、stall 原因 |
| PCIe | `nvidia-smi nvlink/--query-gpu=pcie.link.gen.current` | 跌档到 Gen3 = 性能减半 |
| NIC | `mlnx_perf`、`ethtool -S` | `rx_pause`、`tx_pause`、`rx_discards` |
| 网络 | 交换机 PFC/ECN 计数、buffer occupancy | WRED drop、PFC storm |
| 算法 | NCCL_ALGO / NCCL_PROTO / NCCL_TREE_THRESHOLD | Ring vs Tree 选择是否合理 |
| 拓扑 | `NCCL_TOPO_DUMP_FILE` | Chunk size、channel 数是否退化 |
### 2.3 根因层级(按频率排序)
1. **PFC 反压 / 死锁**:某上联口拥塞 → pause 帧扩散 → 全网慢
2. **ECMP hash 不均**:大流 elephant flow 集中在单链路,其它空闲
3. **DCQCN 参数失配**:Kmin/Kmax/Pmax 设置过激 → 频繁限速
4. **NCCL 算法退化**:消息 size 在 tree/ring 切换阈值附近抖动
5. **GDR 未生效**:`NCCL_NET_GDR_LEVEL` 降级到 CPU 中转,带宽腰斩
6. **PCIe 跨 Socket**:数据走 UPI (~20GB/s) 而非 PCIe Gen4 x16 (~32GB/s)
7. **机柜内 NIC-GPU 不同 Root Complex**:仅能走 CPU memcpy
### 2.4 处置动作
- 短期:把慢节点所在 rail 从训练拓扑中隔离(`NCCL_IB_HCA` 黑名单)
- 中期:让网络侧抓取 PFC 风暴源头,必要时回滚 DCQCN 参数
- 长期:补 `nccl-tests` 常态巡检 + 慢节点自动进隔离池
---
## NCCL Hang(卡死 / wait deadlock)
### 3.1 典型现象
- 所有 rank 全部处于 `cudaStreamSynchronize` 或 `ncclGroupEnd`,无 CPU,GPU 利用率跌到 0
- `py-spy dump` 显示栈停在 `all_reduce` / `broadcast`
- 超时后被 `NCCL_ASYNC_ERROR_HANDLING` / `watchdog` 拉起,或直接 silent hang
- 持续 30 分钟以上无任何日志推进
### 3.2 定位三板斧
1. **抓栈**:所有节点 `py-spy dump --pid $PID` + `gdb -p` / `cuda-gdb`
2. **抓网**:交换机端口镜像 + `ibdump` 10 秒,看 QP 是否还在收发
3. **抓状态**:`NCCL_DEBUG=TRACE` + `NCCL_DEBUG_SUBSYS=ALL`;启用 NCCL 2.20+ 的 `flight recorder`
### 3.3 根因层级
1. **集合通信语义不一致**:rank 间 group call 顺序 / 参数不一致(size、dtype、count 错位)
2. **单张卡 ECC / Xid**:一张 GPU 悄悄退出队列,其它 rank 无限等待
3. **PFC 死锁**:buffer 互相等待,整条路径静默
4. **交换机闪断**:BFD 超时前的 RTO 重传耗尽
5. **应用层 bug**:DataLoader/Checkpoint 阻塞在主线程,通信 stream 被饿死
6. **框架层**:DeepSpeed / Megatron pipeline bubble 未对齐
### 3.4 处置动作
- 立刻:保留现场(禁止先重启!)→ 触发 `nvidia-smi --query-remapped-rows`、`dmesg | grep -i xid`
- 30 秒内:全机 `py-spy dump` → 对比找出"最先停住的那个 rank"
- 2 分钟:按该 rank 的栈反推是等网络、等 GPU 还是等 CPU
---
## 通用排查矩阵
| 层级 | 关键信号 | 首选工具 | 负责角色 |
|---|---|---|---|
| 硬件 | Xid、ECC、LnkSta 跌档 | `nvidia-smi`、`dmesg`、`mlxlink` | SRE |
| 拓扑 | `topo -m`、NUMA、ACS | `nvidia-smi topo`、`lstopo` | 平台 |
| 协议 | QP 状态、MTU、PSN | `ibv_*`、`show_gids` | AI Infra |
| 网络 | PFC / ECN / discards | 交换机计数、`mlnx_perf` | 网络 |
| 软件 | NCCL / driver / OFED 版本 | `nccl-tests`、版本清单 | AI Infra |
| 调度 | 绑核、亲和、资源隔离 | K8s topology manager | 平台 |
| 框架 | group call、pipeline、ckpt | `py-spy`、`torch.profiler` | 算法 |
---
# NCCL 集合通信算子总结
NCCL(NVIDIA Collective Communications Library)主要提供面向多 GPU / 多机场景的**集合通信(collective communication)**能力,常用
于深度学习训练中的梯度同步、参数分发和结果聚合。
## 1. 核心集合通信算子
| 算子 | 含义 |典型作用 | 数据流特征 |
|---|---|---|---|
| **Broadcast** | 广播 | 将一个 root GPU 上的数据复制到所有 GPU | 一发多收 |
| **Reduce** |归约 | 将所有 GPU 上的数据按某种规约操作汇总到 root GPU | 多发一收 |
| **AllReduce** | 全归约 |先做 Reduce,再将结果分发给所有 GPU | 多发多收 |
| **AllGather** | 全收集 | 每个 GPU 提供一份数据,最终所有 GPU 拿到全部数据拼接结果 | 多发多收,拼接 |
| **ReduceScatter** |归约后分发 |先对所有 GPU 数据做规约,再把结果切分后分给各 GPU | 多发多收,规约+切分 |
| **Scatter** | 分发 | root GPU 将一整块数据切分后分给各 GPU | 一发多收,切分 |
| **Gather** | 汇聚 | 所有 GPU 的数据收集到 root GPU 并拼接 | 多发一收,拼接 |
| **AllToAll** | 全交换 | 每个 GPU 给其他所有 GPU发送不同分片,并接收来自所有 GPU 的分片 | 全互发 |
## 2. 各算子说明
### 2.1 Broadcast
> 把 root rank 上的一份数据复制到通信域中的所有 rank。
- 输入:只有 root 的源数据有效
- 输出:所有 rank 拥有相同数据
- 常见用途:
- 初始化模型参数
- 同步配置、随机种子相关状态
### 2.2 Reduce
> 把所有 rank 上的数据做规约运算,结果只保留在 root rank。
- 支持的规约操作通常包括:
- `sum`
- `prod`
- `max`
- `min`
- `avg`(某些框架层封装提供)
- 常见用途:
-统计全局 loss
- 汇总指标到主卡
### 2.3 AllReduce
> 所有 rank 的数据先规约,再把规约结果返回给每个 rank。
- 最常见的 NCCL 算子之一
- 在数据并行训练中用于:
- 梯度同步
- 参数统计同步
- 等价理解:
- `Reduce + Broadcast`
### 2.4 AllGather
> 每个 rank 提供自己的一段数据,最终所有 rank 收到所有 rank 的数据拼接结果。
- 输入:每个 rank 一份局部数据
- 输出:每个 rank 拿到完整拼接后的全量数据
- 常见用途:
- 收集分片 embedding
- 张量并行中的激活/特征拼接
### 2.5 ReduceScatter
>先对所有 rank 的对应数据做规约,再把结果切片分发给各 rank。
- 等价理解:
- `AllReduce + Scatter`
- 相比直接 AllReduce:
- 通常能减少后续冗余拷贝
- 更适合分片优化场景
- 常见用途:
- ZeRO / 分片优化器
- 张量并行、序列并行中的梯度或激活切分
### 2.6 Scatter
> root rank 将一整块数据分片后发送给所有 rank。
- 输入:root 上完整数据
- 输出:每个 rank 得到自己的那一片
- 常见用途:
- 数据分块下发
- 某些参数分片初始化
### 2.7 Gather
> 各 rank 将本地数据发送到 root rank,由 root 拼接成完整结果。
- 输入:每个 rank 一份局部数据
- 输出:root 上完整拼接数据
- 常见用途:
- 收集局部结果
- 推理或评测时汇总输出
### 2.8 AllToAll
> 每个 rank 都向其他所有 rank 发送不同的数据块,同时从其他所有 rank 接收数据块。
- 通信模式最复杂
- 常见用途:
- Mixture of Experts(MoE)中的 token dispatch
- 张量重排 / 数据重分布
## 3. 常见规约操作(Reduction Ops)
NCCL 的 `Reduce` / `AllReduce` / `ReduceScatter` 等算子通常配合以下规约类型:
|规约类型 | 含义 |例子 |
|---|---|---|
| **sum** | 求和 | 梯度累加 |
| **prod** | 求积 | 较少使用 |
| **max** |取最大值 |统计最大值 |
| **min** |取最小值 |统计最小值 |
| **avg** | 求平均 | 常作为 `sum` 后再除 `world size` 的语义封装 |
## 4.训练场景里的典型对应关系
|训练场景 | 常用 NCCL 算子 |
|---|---|
| 数据并行梯度同步 | **AllReduce** |
| 模型初始化参数同步 | **Broadcast** |
| 分布式指标汇总 | **Reduce / AllReduce** |
| 张量并行结果拼接 | **AllGather** |
| 分片梯度规约 | **ReduceScatter** |
| MoE token 路由 | **AllToAll** |
## 5. 算子之间的关系
| 算子 | 可近似拆解为 |
|---|---|
| **AllReduce** | `Reduce + Broadcast` |
| **ReduceScatter** | `Reduce + Scatter` |
| **AllGather** | `Gather + 广义上的全员可见` |
| **AllToAll** | 更一般化的多对多交换 |
## 6. 一句话理解
- **Broadcast**:一份数据发给所有人
- **Reduce**:所有人的数据汇总到一个人
- **AllReduce**:所有人的数据汇总后,每个人都拿到结果
- **AllGather**:每个人的分片拼成完整数据,所有人都拿到
- **ReduceScatter**:先汇总,再把结果分片给每个人
- **AllToAll**:每个人都和其他所有人交换不同的数据
NCCL 集合通信总结