1. 智算集群为什么需要一套“听诊器”
搞过大规模训练的人都有一个共同体会:集群规模一旦上去,故障就不再是“某台机器坏了”这么简单,而是变成了一种系统性、间歇性、难以复现的疑难杂症。你可能遇到过训练跑了三天突然 loss 炸了,重启之后又好了;也可能遇到过某个节点吞吐量莫名其妙比其他节点低 30%,但查遍日志什么错误都没有。这类问题靠传统的nvidia-smi和dmesg根本定位不了,你需要一套专门为 AI 集群设计的“听诊器”——这就是Benchmark、监控与故障诊断体系存在的意义。
这套体系解决的核心问题有三个:第一,性能基线问题,你得知道集群在健康状态下应该跑出什么数字,才能判断现在是不是有问题;第二,实时可观测性问题,训练过程中的 GPU 利用率、显存带宽、NVLink 流量、网络 RDMA 吞吐这些指标必须持续采集,而不是出事了才去看;第三,故障归因问题,当性能下降发生时,能快速定位到是计算、通信、存储还是调度层面的瓶颈。
适合读这篇内容的人包括:正在搭建或运维 GPU 集群的工程师、负责大模型训练基础设施的 SRE、需要做集群验收和性能调优的技术负责人,以及想了解 AI 集群运维体系长什么样的开发者。我会从整体设计思路讲到具体实操,包括 NCCL 测试怎么做、Prometheus 怎么采集 GPU 指标、常见故障怎么排查,尽量把踩过的坑都摊开讲。
2. 整体设计思路:从“事后救火”到“事前体检”
2.1 为什么传统监控方案在 AI 集群上不够用
传统 IDC 监控关注的是 CPU、内存、磁盘、网络带宽这些通用指标,用 Zabbix 或者基础的 Prometheus 就能覆盖。但 AI 集群的负载特征完全不同:GPU 是核心计算资源,它的利用率、显存占用、温度、功耗、ECC 错误、NVLink 带宽这些指标传统工具根本采集不到。更关键的是,AI 训练是集合通信密集型的负载,一次 AllReduce 操作涉及成百上千张卡同步,任何一张卡或任何一条链路出现微小的性能抖动,都会拖慢整个通信组,进而拖慢整个训练任务。
我见过一个真实案例:一个 64 卡集群训练吞吐比预期低了 15%,查了一周没找到原因,最后用 NCCL 的带宽测试逐对检测,发现其中两台机器之间的 InfiniBand 链路协商速率从 200Gbps 降到了 100Gbps,原因是其中一端的线缆接头有轻微松动。这种问题,传统监控完全看不到,只有专门的集合通信 Benchmark 才能暴露出来。
所以 AI 集群的“听诊器”体系必须包含三个层次:基准测试层(Benchmark,回答“应该多快”)、持续监控层(Monitoring,回答“现在多快”)、故障诊断层(Diagnosis,回答“为什么变慢”)。三者缺一不可,而且必须形成闭环——Benchmark 提供基线,监控对比基线发现异常,诊断定位根因。
2.2 三层体系的具体分工与工具选型
基准测试层的核心工具是 NCCL Tests、GPU Burn、STREAM Benchmark、FIO(存储)、iperf3(网络)。其中 NCCL Tests 是重中之重,因为集合通信性能直接决定分布式训练效率。NCCL Tests 包含 all_reduce、all_gather、broadcast、reduce_scatter 等多个测试项,可以测不同消息大小下的带宽和延迟。
持续监控层的标准组合是 Prometheus + Grafana + DCGM Exporter。DCGM 是 NVIDIA 的数据中心 GPU 管理器,它暴露的指标非常全面,包括 GPU 利用率、显存使用、SM 活跃度、Tensor Core 活跃度、NVLink 带宽、PCIe 带宽、ECC 错误计数、XID 错误等。Prometheus 负责拉取和存储,Grafana 负责可视化。对于网络层,可以加上 InfiniBand 的 performance counters 采集;对于节点层,node_exporter 负责 CPU、内存、磁盘指标。
故障诊断层则更多依赖工具组合和排查经验。常用手段包括:NCCL 的 debug 日志(NCCL_DEBUG=INFO)、nvidia-smi -q的详细输出、DCGM 的诊断模式(dcgmi diag)、XID 错误码查询、以及针对性的微基准测试。这一层没有银弹,更多是靠体系化的排查流程和积累的经验。
注意:工具选型不要贪多求全。我见过有团队同时跑了三套监控系统,结果数据互相矛盾,排查时反而更混乱。建议以 Prometheus + DCGM Exporter 为核心,其他工具按需补充。
2.3 基线建立:一切诊断的前提
没有基线的监控就是一堆没有意义的数字。建立基线的方法是在集群健康且空闲的状态下,跑一轮完整的 Benchmark 套件,记录下每个测试项的性能数据。这个基线要包括:单卡 FP16/FP32 算力(用 GPU Burn 或专门的算力测试)、单机内 NVLink 带宽、跨机 InfiniBand 带宽(用 NCCL Tests 的 all_reduce)、存储读写带宽(用 FIO)、以及典型训练任务的吞吐(tokens/sec 或 samples/sec)。
基线数据要存档,并且标注测试时的环境信息:驱动版本、CUDA 版本、NCCL 版本、交换机固件版本、拓扑结构。因为任何一项变更都可能导致基线漂移,比如 NCCL 版本升级后 all_reduce 带宽可能提升也可能下降,没有版本标注的基线数据是没有参考价值的。
3. 核心细节解析:NCCL Benchmark 与 GPU 监控实操
3.1 NCCL Tests 的正确打开方式
NCCL Tests 的编译很简单,从官方仓库 clone 下来make就行,但关键在于怎么跑才有意义。很多人直接跑一个默认参数的 all_reduce 就完事了,这样得到的数据参考价值有限。正确的做法是覆盖多个维度:
- 消息大小:从 8 bytes 到 8 GB,覆盖小消息(延迟敏感)和大消息(带宽敏感)两个区间
- GPU 数量:至少测 2 卡、8 卡(单机)、16 卡、32 卡、64 卡(跨机),观察扩展效率
- 拓扑感知:用
NCCL_TOPO_DUMP_FILE导出拓扑,确认 NCCL 是否识别到了正确的 NVLink 和 InfiniBand 路径
一个典型的 all_reduce 测试命令如下:
# 8 卡单机 all_reduce 测试 ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 8 # 跨机测试,需要 mpirun 或 torchrun 启动 mpirun -np 16 -H node1:8,node2:8 \ -x NCCL_DEBUG=INFO \ -x NCCL_IB_HCA=mlx5_0,mlx5_1 \ ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 1参数解释:-b是起始消息大小,-e是结束大小,-f是倍增因子(2 表示每次翻倍),-g是每进程使用的 GPU 数。跨机测试时-g 1表示每个进程用一张卡,总共 16 个进程对应 16 张卡。
跑完之后重点看两个数字:algbw(算法带宽)和busbw(总线带宽)。busbw 更能反映实际链路利用率,计算公式是busbw = algbw * 2 * (n-1) / n,其中 n 是参与通信的 GPU 数。对于 8 卡 NVLink 全互联的机器,busbw 应该接近 NVLink 的理论带宽;对于跨机 InfiniBand,busbw 应该接近 IB 链路带宽的 80% 以上。
实操心得:跑 NCCL Tests 之前一定要确认 GPU 处于空闲状态,并且锁定频率。用
nvidia-smi -lgc锁定 GPU 时钟,用nvidia-smi -lmc锁定显存时钟,否则 GPU 会因为功耗管理动态调频,导致测试结果波动很大。我一般会把时钟锁在基频,这样测出来的数据可比性最强。
3.2 DCGM Exporter 部署与关键指标解读
DCGM Exporter 的部署方式取决于你的环境。如果是 Kubernetes 集群,用 Helm chart 部署最方便;如果是裸机,可以用 Docker 跑:
docker run -d --gpus all --rm \ -p 9400:9400 \ --name dcgm-exporter \ nvcr.io/nvidia/k8s/dcgm-exporter:3.3.0-3.2.0-ubuntu22.04跑起来之后访问http://localhost:9400/metrics就能看到所有指标。指标很多,但真正需要重点关注的其实就那么几个:
| 指标名称 | 含义 | 异常判断 |
|---|---|---|
| DCGM_FI_DEV_GPU_UTIL | GPU 计算利用率 | 持续低于 80% 可能有瓶颈 |
| DCGM_FI_DEV_MEM_COPY_UTIL | 显存带宽利用率 | 接近 100% 说明显存瓶颈 |
| DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL | NVLink 总带宽 | 突然下降可能是链路问题 |
| DCGM_FI_DEV_PCIE_REPLAY_COUNTER | PCIe 重传计数 | 持续增长说明 PCIe 有问题 |
| DCGM_FI_DEV_XID_ERRORS | XID 错误码 | 非零值需要立即排查 |
| DCGM_FI_DEV_ECC_DBE_VOL_TOTAL | 显存双比特错误 | 非零值说明显存硬件故障 |
| DCGM_FI_DEV_POWER_USAGE | 功耗 | 异常低可能是降频 |
| DCGM_FI_DEV_GPU_TEMP | 温度 | 超过 85 度需要关注散热 |
这些指标接入 Prometheus 之后,在 Grafana 上配置看板。我建议至少做三个看板:集群总览(所有 GPU 的利用率热力图)、单节点详情(单机 8 卡的各项指标曲线)、异常告警(XID 错误、ECC 错误、温度超限的实时列表)。
3.3 Prometheus 告警规则配置要点
监控没有告警等于没有监控。Prometheus 的告警规则用 YAML 配置,以下是我在实际环境中验证过有效的几条核心规则:
groups: - name: gpu_alerts rules: - alert: GPUXIDError expr: DCGM_FI_DEV_XID_ERRORS > 0 for: 1m labels: severity: critical annotations: summary: "GPU XID error detected on {{ $labels.instance }}" - alert: GPUTemperatureHigh expr: DCGM_FI_DEV_GPU_TEMP > 83 for: 5m labels: severity: warning annotations: summary: "GPU temperature high on {{ $labels.instance }}" - alert: GPUMemoryECCDoubleBit expr: DCGM_FI_DEV_ECC_DBE_VOL_TOTAL > 0 for: 1m labels: severity: critical annotations: summary: "GPU double-bit ECC error on {{ $labels.instance }}" - alert: NCCLBandwidthDrop expr: rate(DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL[5m]) < 100e9 for: 10m labels: severity: warning annotations: summary: "NVLink bandwidth dropped on {{ $labels.instance }}"注意:告警阈值不要照搬网上的配置。不同型号的 GPU 温度阈值不同,A100 和 H100 的功耗曲线也不一样。建议先跑一周的监控,观察正常波动范围,再设定阈值。告警太敏感会导致“狼来了”效应,运维人员逐渐忽略告警,这比没有告警更危险。
4. 故障诊断实战:从现象到根因的排查路径
4.1 训练吞吐下降的排查决策树
训练吞吐下降是最常见的故障现象,但原因可能五花八门。我总结了一套排查决策树,按顺序执行可以覆盖 90% 以上的场景:
第一步,确认是全局问题还是局部问题。对比所有节点的 GPU 利用率,如果所有节点都低,说明是全局性问题(可能是数据加载瓶颈、通信瓶颈、或者调度问题);如果只有部分节点低,说明是局部性问题(可能是某张卡降频、某条链路故障)。
第二步,检查 GPU 状态。用nvidia-smi -q查看是否有降频(clocks throttle reason)、是否有 ECC 错误、是否有 XID 错误。特别关注Clocks Throttle Reasons字段,如果显示HW Slowdown或SW Thermal Slowdown,说明是散热或功耗问题。
第三步,检查通信。在训练脚本里设置NCCL_DEBUG=INFO和NCCL_DEBUG_SUBSYS=ALL,观察 NCCL 初始化时选择的通信路径。如果发现 NCCL 没有走 InfiniBand 而是走了 TCP socket,那性能肯定差。常见原因是NCCL_IB_HCA没设置对,或者 IB 驱动有问题。
第四步,检查存储。如果数据加载是瓶颈,GPU 利用率会呈现周期性波动(等待数据时降到 0,数据来了又升上去)。用iostat和fio检查存储带宽是否达到预期。
第五步,检查 CPU 和内存。数据预处理如果放在 CPU 上做,CPU 可能成为瓶颈。用htop看 CPU 利用率,如果某个核跑满而 GPU 在等,那就是数据加载的问题。
4.2 XID 错误码速查与处理
XID 错误是 NVIDIA GPU 的硬件级错误码,每个码对应不同的故障类型。以下是我实际遇到过的高频 XID 错误:
| XID 码 | 含义 | 处理方式 |
|---|---|---|
| 13 | Graphics engine exception | 通常是应用程序 bug,检查 CUDA 代码 |
| 31 | GPU memory page fault | 显存访问越界,检查 kernel 代码 |
| 43 | GPU stopped processing | GPU 挂起,需要重置 GPU |
| 48 | Double-bit ECC error | 显存硬件故障,需要更换 GPU |
| 63 | ECC page retirement | 显存页退役,记录并观察 |
| 74 | NVLink error | NVLink 链路故障,检查物理连接 |
| 79 | GPU has fallen off the bus | GPU 掉卡,通常是硬件或供电问题 |
| 92 | High single-bit ECC error rate | 单比特错误率过高,可能发展为双比特 |
| 94 | Contained ECC error | 可纠正的 ECC 错误,记录观察 |
| 95 | Uncontained ECC error | 不可纠正的 ECC 错误,需要重置 GPU |
遇到 XID 错误,第一步是记录错误码和发生时间,第二步是查 NVIDIA 官方的 XID 错误码文档确认含义,第三步是根据严重程度决定是重置 GPU、重启节点还是报修硬件。XID 48 和 95 基本意味着 GPU 需要更换,XID 74 需要检查 NVLink 线缆和连接器。
4.3 NCCL 通信故障的典型场景
NCCL 相关的故障有几个经典场景,我逐个说一下排查方法。
场景一:NCCL 初始化超时。训练启动时卡在 NCCL 初始化阶段,日志显示NCCL INFO Bootstrap之后就没有下文了。这通常是网络连通性问题,检查所有节点之间的 SSH 免密是否配置正确、防火墙是否放行了 NCCL 使用的端口范围、IB 网络是否正常。可以用ibstat检查 IB 卡状态,用ibping测试节点间连通性。
场景二:NCCL 走了错误的通信路径。日志显示NCCL INFO NET/Socket而不是NCCL INFO NET/IB,说明 NCCL 没有使用 InfiniBand。检查NCCL_IB_HCA环境变量是否指向了正确的 HCA 设备,检查NCCL_IB_DISABLE是否被设为了 1,检查 IB 驱动是否加载(lsmod | grep ib)。
场景三:AllReduce 带宽远低于预期。用 NCCL Tests 测出来的 busbw 只有理论值的 30%。可能原因包括:GPU 降频、NVLink 链路降速、IB 交换机拥塞、NCCL 算法选择不当。可以尝试设置NCCL_ALGO=Ring或NCCL_ALGO=Tree强制使用不同算法,看是否有改善。也可以设置NCCL_PROTO=LL或NCCL_PROTO=Simple切换协议。
场景四:训练过程中随机出现 NCCL timeout。这种间歇性故障最难排查。常见原因是某条链路有丢包或误码,导致偶发的通信超时。检查 IB 的 error counters(perfquery命令),如果SymbolErrorCounter或LinkErrorRecoveryCounter在增长,说明链路质量有问题。也可能是 GPU 偶发降频导致通信超时,检查是否有 XID 错误或温度告警。
实操心得:NCCL 的日志级别用
NCCL_DEBUG=WARN就够了,INFO级别日志量太大,在千卡集群上会把日志系统冲垮。只有在排查特定问题时才临时开到INFO,并且只对可疑节点开。另外NCCL_DEBUG_FILE可以把日志写到文件而不是 stderr,方便后续分析。
5. 监控体系的持续运营与常见问题
5.1 监控数据采集频率与存储规划
Prometheus 的采集频率直接影响监控精度和存储成本。对于 GPU 指标,我建议采集间隔设为 15 秒,这个精度足以捕捉到大多数性能波动,同时不会产生太大的存储压力。按 1000 张 GPU 计算,每张卡约 50 个指标,15 秒采集一次,每天产生的数据量大约是 1000 × 50 × 5760 = 2.88 亿个数据点。Prometheus 的压缩率大约是每样本 1-2 字节,所以每天约 300-600 MB,保留 30 天需要 10-20 GB 存储,完全可以接受。
如果需要更高精度的数据(比如排查瞬时的性能抖动),可以临时把采集间隔调到 1 秒,但只针对可疑节点,排查完就调回去。长期 1 秒采集会导致存储爆炸。
Grafana 看板的配置也有讲究。集群总览看板不要放太多面板,否则加载慢且信息过载。我一般放四个核心面板:GPU 利用率热力图、GPU 温度分布、XID 错误统计、NCCL 带宽趋势。详细指标放到下钻看板里,需要时再点进去看。
5.2 常见监控问题与排查
问题一:DCGM Exporter 采集不到数据。首先确认容器是否有--gpus all权限,其次确认 NVIDIA 驱动版本和 DCGM 版本是否兼容。DCGM 3.x 需要驱动 450 以上,DCGM 3.3 需要驱动 525 以上。如果驱动版本太低,升级驱动或者降级 DCGM。
问题二:Prometheus 抓取目标显示 down。检查 DCGM Exporter 的端口是否监听(netstat -tlnp | grep 9400),检查 Prometheus 配置的 target 地址是否正确,检查防火墙是否放行了 9400 端口。如果是 Kubernetes 环境,检查 Service 和 Pod 的标签选择器是否匹配。
问题三:Grafana 看板显示 No Data。最常见的原因是时间范围选错了,或者 Prometheus 数据源配置错误。检查 Grafana 的 Data Source 设置,点“Save & Test”确认连接正常。如果数据源正常但还是 No Data,检查查询语句的指标名称是否和 DCGM Exporter 暴露的一致,不同版本的 DCGM Exporter 指标名称可能有差异。
问题四:监控数据与实际不符。比如nvidia-smi显示 GPU 利用率 90%,但 DCGM 显示 60%。这种差异通常是因为采样时间窗口不同。nvidia-smi显示的是瞬时值,DCGM 采集的是采样周期内的平均值。另外 DCGM 的 GPU 利用率定义和nvidia-smi可能略有不同,以 DCGM 为准即可,因为它是专门为数据中心场景设计的。
5.3 故障诊断的自动化尝试
手动排查故障效率低且依赖经验,我尝试过一些自动化手段。最简单的是写一个巡检脚本,定期跑 NCCL Tests 和 GPU 健康检查,把结果写入数据库,发现异常时自动告警。这个脚本用 Python 写就行,核心逻辑是调用subprocess执行测试命令,解析输出,对比基线。
更进一步的做法是用 DCGM 的诊断模式(dcgmi diag),它内置了一套完整的硬件诊断流程,包括 GPU 计算测试、显存测试、PCIe 测试、NVLink 测试等。可以设置成每天凌晨自动跑一次,生成诊断报告。如果诊断不通过,说明硬件可能有问题,提前报修避免训练中断。
不过自动化诊断也有局限。它只能发现已知的、有明确判断标准的问题,对于性能退化这类模糊问题,还是需要人工分析监控数据。我的经验是:自动化负责“发现异常”,人工负责“定位根因”,两者配合效率最高。
6. 一些踩过的坑和实用建议
先说一个最容易被忽略的点:GPU 时钟锁定。很多集群为了省电,默认开启 GPU 的动态调频。这在推理场景没问题,但在训练场景会导致性能波动。我建议在训练节点上通过nvidia-smi -lgc锁定 GPU 时钟到基频或略高于基频,显存时钟也锁定。这样虽然功耗高一些,但性能稳定可预测。实测下来,锁定时钟后 NCCL 带宽测试的波动从 ±15% 降到了 ±3%。
第二个坑是NCCL 版本与驱动的兼容性。NCCL 版本更新很快,新版本通常性能更好,但也可能引入新的 bug。我遇到过升级 NCCL 后 all_reduce 带宽反而下降 20% 的情况,回退版本后恢复正常。所以升级 NCCL 之前一定要在测试环境验证,确认性能不降反升再上生产。另外 NCCL 版本要和 CUDA 版本匹配,CUDA 11.x 配 NCCL 2.10-2.14,CUDA 12.x 配 NCCL 2.16 以上。
第三个坑是InfiniBand 的 PFC 和 ECN 配置。在 RoCE 环境下,PFC(Priority Flow Control)和 ECN(Explicit Congestion Notification)的配置直接影响网络性能。配置不当会导致丢包和重传,进而导致 NCCL 超时。建议参考交换机和网卡厂商的最佳实践文档来配置,不要用默认值。配置完之后用ib_send_bw和ib_send_lat测试一下实际带宽和延迟。
第四个坑是监控数据的保留策略。Prometheus 默认保留 15 天数据,对于故障排查来说可能不够。我建议至少保留 30 天,重要集群保留 90 天。可以用 Prometheus 的 remote write 功能把数据写到长期存储(比如 Thanos 或 VictoriaMetrics),这样既不影响 Prometheus 的性能,又能长期保留数据。
最后一个建议:建立故障知识库。每次排查完一个故障,把现象、排查过程、根因、解决方案记录下来。时间长了这就是团队最宝贵的财富。我现在的团队有一个内部 Wiki,记录了上百个故障案例,新同事遇到问题先查知识库,80% 的情况能直接找到答案。这比任何监控工具都管用。
这套“听诊器”体系不是一次建成的,而是随着集群规模增长和故障经验积累逐步完善的。从最基础的nvidia-smi巡检开始,到部署 DCGM + Prometheus + Grafana,再到建立 NCCL Benchmark 基线和故障知识库,每一步都能实实在在提升集群的可用性和训练效率。