ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

8×B200多卡训练卡死?Fabric Manager版本不一致是隐藏元凶

8×B200多卡训练卡死?Fabric Manager版本不一致是隐藏元凶

这周机房里出了一件让人头疼的事:一台8×B200节点的多卡通信在训练任务启动时直接卡死,NCCL反复等NVLS建起来却始终不成功,所有GPU进程都挂在初始化阶段。排查了一整天,最后定位到Fabric Manager版本不一致——这个看起来不起眼的控制面问题,让NVSwitch的fabric协商直接失败。手头这台8卡B200是NVSwitch互联的HGX平台,单机内通信走NVLink和NVSwitch,根本不经过网卡,所以一开始很多人都往网卡驱动力向猜,浪费了不少时间。

如果你也在维护B200、GB200或者任何带NVSwitch的高密度GPU平台,建议把这篇排查记录存下来。它不光是解决一个卡死问题,更重要的是能帮你理解Fabric Manager在整个多卡通信链路里的位置,以及遇到类似"服务在运行但功能不正常"的故障时,应该从哪一层入手。

1. 现象还原:不是慢,是彻底卡死

1.1 任务启动即hang住的现场

这台8×B200节点是半个月前刚上架的,跑的是我们内部一个千亿参数模型的微调任务。正常情况下,NCCL初始化应该在几十秒内完成,然后GPU利用率会迅速拉起来。但这次我从提交训练脚本开始等,过了5分钟、8分钟、12分钟,任务始终没有进入第一个step。top和nvtop显示CPU侧有一些线程在死等,但8张GPU卡的利用率始终是0%,SM占用接近空,显存也已经按batch分配好了,就是没有任何计算发生。

一开始我以为是数据集加载问题,但kill掉任务后,重新跑一个最简单的all_reduce测试脚本,问题依旧。那么基本可以排除用户代码层面的问题。这台节点用nvidia-smi看,8张卡都是P0状态,温度、功耗、显存频率全部正常。既然硬件上电状态没问题,我立刻怀疑到了通信层。

1.2 第一轮的常见误判方向

遇到这种多卡通信hang死,大家第一反应通常是检查几个点:

  • 驱动版本是不是有问题;
  • NVLink物理链路是不是断了;
  • 网卡/RoCE/IB配置是不是有问题;
  • 还是拓扑里出现异常,导致数据路径绕了远路。

我也按这个顺序查了。nvidia-smi --query-gpu=driver_version --format=csv显示驱动是560.28.03,大部分卡正常;nvidia-smi nvlink -s显示所有link都是ENABLED状态;nvidia-smi topo -m也能正常打印出8卡之间的NVLink拓扑。到这里,物理数据面看起来都是通的。可真正奇怪的是:数据面全通,控制面却没人告诉上层"fabric已经准备好了"。

这种"物理通、逻辑不通"的状态是最容易误导人的。如果你也遇到类似情况,我强烈建议不要继续在数据面花时间,立刻把目光转向NVSwitch的Fabric Manager。

1.3 为什么这时就要开始怀疑FM

NVSwitch平台和普通x86服务器插几块卡完全不一样。普通多卡即使没有FM,GPU之间也能走PCIe或简单的P2P通信。但B200的8卡通信核心是NVSwitch:GPU要先把数据交到NVSwitch芯片,由NVSwitch在芯片内部完成路由和广播。问题是,NVSwitch本身是一个"没有大脑"的交换芯片,路由规则和广播域必须由Fabric Manager服务在初始化阶段下发。

所以当nvlink物理链路正常、但NCCL的NVLS域一直建不起来时,问题基本就锁定在FM这一层。它可能是服务没起来,可能是和驱动版本不匹配,也可能是和NVSwitch固件协商失败。但无论如何,应该先看FM,而不是去反复测试网络。

2. NVLS链路为什么依赖Fabric Manager,版本不一致为什么是硬伤

2.1 NVLS在8卡B200里承担什么角色

有些人会把NVLS直接等同于NVLink,其实不太准确。NVLS(这里指基于NVLink Switch构建的NVLink域,以及配合NCCL实现的NVLS集合通信路径)是一个从GPU到NVSwitch再到远端GPU的完整通信域。训练框架里的NCCL会向驱动申请建立一个NVLS domain,获取这个domain里所有GPU的ID,然后通过NVSwitch进行多对多的集合通信,比如AllReduce和AllGather。

这个domain不是凭空就能创建的。FM必须先让NVSwitch处于"fabric healthy"状态,然后驱动才能拿到domain所需的拓扑和路由表。整个链路可以简单画成:

  • GPU上的CUDA应用发起集合通信;
  • NCCL询问驱动是否存在可用的NVLS路径;
  • 驱动查询FM管理的NVSwitch状态;
  • FM返回fabric domain信息;
  • NCCL确认domain可用后,才真正下发通信数据。

只要FM那一步出了问题,驱动拿不到合法的domain ID,NCCL就会一直等待。在8卡B200这种封闭环境里,它通常不会马上报错回退,而是反复重试。这也是我们看到hang死而不是报错的原因。

2.2 FM版本不一致到底破坏了什么

FM版本不一致,通常有两种场景。

第一种单节点内驱动和FM版本不匹配。NVIDIA对Fabric Manager有一个很硬性的要求:FM的版本必须和GPU驱动版本严格对齐。比如驱动是560.28.03,FM就必须是560系列里的对应build号。如果驱动升到了560,FM还停留在555,FM加载时会发现驱动接口版本对不上,NVSwitch初始化就失败。

第二种是跨节点或跨NVSwitch的FM版本不一致。多机多卡要通过NVSwitch构建跨节点fabric时,所有节点上的FM必须是同一版本,否则节点之间进行fabric信息交换时,版本协商会失败。这个问题在单机8卡B200上也可能出现,因为一台HGX主板上有多个NVSwitch芯片,FM要和每一颗芯片建立会话,如果芯片固件版本不一致,一样会出现协商失败。

打个比方,FM和NVSwitch之间的关系有点像路由器和控制器:交换机自己能转发数据,但路由表要由控制器统一下发。如果控制器说"我用协议版本1.3",交换机固件说"我理解的是1.2",双方虽然都能开机,但一交换报文就互相看不懂,控制面直接断掉。NVSwitch的fabric协商就是类似的道理。

2.3 为什么NCCL会hang住而不是迅速报错

这是整个故障最隐蔽的地方。如果FM完全没启动,NCCL通常在几十秒内就会报"fabric not available"然后退出。但这次FM服务本身是active (running)的,驱动也能通过nvidia-smi看到NVSwitch设备。NCCL每次查询NVLS domain,得到的都是类似"正在初始化"或"fabric state not ready"的中间态信息,于是它只能等待下一次查询。外部表现就是所有rank都挂在集合通信初始化上。

有人会想到调大NCCL_TIMEOUT来绕过,但这是控制面协商失败,不是慢。等待再久也不可能成功。还有人想用NCCL_P2P_DISABLE=1强制回退,但这些环境变量只是让NCCL不用NVLS,问题在于驱动层面已经知道Fabric Manager异常,系统启动之初的fabric分配就受了影响,并不是只在NCCL这一层做选择。所以遇到这种情况,唯一有效的处理是让FM真正健康起来。

3. 完整排查链路:一步一步把FM拽出来

3.1 先从NCCL日志拿到怀疑线索

真正拿到方向是在我设置了NCCL_DEBUG=INFO重跑之后。日志里反复出现这样的内容:

[0] NCCL INFO NVLS: initialization failed, retrying... [0] NCCL INFO NVLS: waiting for fabric ... [1] NCCL INFO NET/OFI Selecting ...

虽然它没有直接告诉你"FM版本不对",但已经很明确地把问题引向了NVLS的fabric初始化阶段。进一步用NCCL_DEBUG=TRACE,还能看到类似nvlsQueryFabric超时的信息。到这一步,我就不再碰网络和PCIe了,基本锁定NVSwitch控制面。

3.2 查看FM服务状态和日志

接下来,检查FM服务。在Ubuntu 22.04上,模块名是nvidia-fabricmanager。先用systemctl status看服务:

systemctl status nvidia-fabricmanager

输出显示服务是active (running)。当时我顿了一下:服务在跑,为什么还会出问题?后来才意识到,"服务在跑"只是systemd层面的状态,FM用户态进程起来之后,还需要和内核态驱动、NVSwitch固件做多轮握手。只要握手失败,服务进程不会自杀,只是在日志里反复报错。

于是继续看FM日志。默认路径在/var/log/fabricmanager.log,这是FM自己的运行日志:

grep -i "error\|version\|mismatch" /var/log/fabricmanager.log | tail -50

日志里出现了几行关键信息:

ERROR: Fabric Manager version mismatch with GPU driver version. ERROR: NVSwitch failed to initialize the fabric: version negotiation failed. ERROR: Fabric state NOT healthy.

到这里基本可以断定:不是FM没起,而是FM带病运行,版本不匹配导致NVSwitch初始化不完整。

3.3 检查三层版本:驱动、FM、NVSwitch固件

为了确认到底哪里不一致,我把版本信息完整拉了一遍,整理成一张对照表:

检查对象常用命令本机结果
GPU驱动版本nvidia-smi --query-gpu=driver_version --format=csv560.28.03
FM软件包版本dpkg -l | grep fabricmanager555.28.02
NVSwitch固件状态nvidia-smi -q | grep -iA2 "nvswitch"Firmware可见,但Fabric State不是Healthy

从表里一眼就能看出问题:驱动已经是560系列,而FM包还是555系列。虽然服务进程还在"运行",但内部使用的驱动接口版本完全不同,NVSwitch的fabric初始化自然无法完成。

另外,也得看看NVSwitch固件本身。在B200平台上,如果FM版本和NVSwitch固件版本不一致,nvidia-smi -q中NVSWITCH部分的Fabric State可能会显示NOT Supported。我们顺便检查了同批次另一台节点,发现那台的FM版本是560.28.03,正好匹配。两边一对比,版本不一致已经是实锤。

3.4 尝试过的几个无效操作

排查过程中我也走了几步弯路,记录一下免得大家重复踩:

  • 尝试重启FM服务:systemctl restart nvidia-fabricmanager。服务确实重启了,但软件版本没变,旧版本还是旧版本,故障依旧。
  • 尝试加载nvidia-peermem模块,想改善内存注册路径。但这个问题发生在NVSwitch控制面,和数据路径无关,没有任何效果。
  • 尝试在训练脚本里加NCCL_TIMEOUT=3600,希望多等一会儿能跳过。结果等到天荒地老也过不去,因为fabric协商失败是一种确定性的失败,不是偶发超时。

这几个无效操作反而帮我确认了:这是一个控制面版本兼容性问题,必须从版本对齐下手。

4. 判定版本不一致的正确姿势:别只看包名,要看实际加载状态

4.1 一套可复用的检查流程

这次故障之后,我整理了一套可以在B200、A100/A800等NVSwitch平台上通用的快检流程:

# 1. 检查GPU驱动版本 nvidia-smi --query-gpu=driver_version --format=csv # 2. 检查FM包名(Ubuntu/Debian系) dpkg -l | grep fabricmanager # 3. 检查FM服务运行状态 systemctl status nvidia-fabricmanager # 4. 检查FM日志中是否有版本相关错误 grep -i "version\|mismatch\|error" /var/log/fabricmanager.log | tail -30

如果第1步和第2步里的版本号不在同一个release系列,直接判定为异常。哪怕只差一个小版本,也有可能导致NVLS建不起来。不要因为第3步显示服务在运行就觉得没问题,很多版本校验发生在FM进程内部,外部看起来一切正常。

4.2 版本号里的大小版本陷阱

NVIDIA驱动版本号通常长这样:560.28.03。FM的Debian包名是nvidia-fabricmanager-560,注意这里的560只是driver分支号,不是完整build号。很多人看到包名带560就认为匹配,但FM真正的详细版本可能在包内部,需要通过dpkg -s或cat /etc/fabricmanager_version查看。如果驱动是560.28.03,FM包是560.28.02,虽然主分支一致,但build号差了一格,在一些严格校验的场景下同样会出问题,只是更隐蔽。

我和同事后来总结了一个更稳妥的办法:不要只看包名,要看nvml或FM日志中实际报告的API版本。FM在启动时会把检测到的driver interface版本打印出来,如果和自身版本不匹配,日志里一定有提示。所以日志才是最终依据。

4.3 FM版本与NVSwitch固件的关系

NVSwitch固件由厂商烧录,但在运行时会通过FM向driver暴露一组Fabric API版本。FM版本过低,就无法正确解析新固件里的能力位,导致某些fabric feature被标记为不可用;FM版本过高,又可能访问一个已经不存在的寄存器接口。两种情况都会让NVLS domain无法创建。

建议检查时一定要执行:

nvidia-smi -q | grep -iA2 "nvswitch\|fabric"

如果Fabric State不是Healthy或者Enabled,就要立刻去FM日志里找版本协商错误。我还遇到过一种情况:nvidia-smi显示的NVSwitch固件版本正常,但/var/log/fabricmanager.log里反复报fabric partition mismatch。这说明FM管理下的partition信息和OVS/NVSwitch实际状态不一致,这种状态往往需要把这台节点下电、重新让NVSwitch上电才能完全恢复。

5. 修复操作:把FM替换成与驱动严格匹配的版本,NVLS秒恢复

5.1 标准修复步骤

找到根因之后,修复其实很直接。以Ubuntu 22.04 + NVIDIA driver 560.28.03为例,把原来的555系列FM卸载,安装560系列FM:

# 1. 卸载旧FM apt purge nvidia-fabricmanager-555 # 2. 安装与驱动匹配的FM apt install nvidia-fabricmanager-560 # 3. 重载systemd并启动服务 systemctl daemon-reload systemctl enable --now nvidia-fabricmanager # 4. 确认服务状态 systemctl status nvidia-fabricmanager

如果驱动是RPM系的发行版,比如Rocky Linux或SLES,命令对应为rpm -e和dnf install nvidia-fabricmanager-560,核心思路一样。我习惯在安装完成之后先不急着跑训练,等上10到20秒,让FM完成NVSwitch的fabric初始化。这个过程里可以观察/var/log/fabricmanager.log的尾部,正常情况下会出现类似:

INFO: NVSwitch fabric is ready. INFO: Fabric state Healthy.

这类日志出现后,才说明控制面真正恢复了。

5.2 验证NVLS真正建起来

服务状态正常还不够,我们最终要确认的是NVLS能建起来。建议直接跑一个小工具验证,比如NVIDIA官方的nvbandwidth,指定NVLink模式:

nvbandwidth -m nvlink

正常情况下可以看到8张卡两两之间出现bandwidth测试结果,如果有Failed to initialize NVLS之类的报错,说明fabric还是没完全恢复。更直接的办法是重新跑训练任务,设置NCCL_DEBUG=INFO,观察是否出现NVLS: initialized或NVLS: Success。

我在这次操作完以后,NCCL初始化时间从"永久hang死"变成了大概20秒内完成,8卡之间NVLink读带宽恢复到每条链路约180GB/s,allreduce吞吐也回到了预期范围。这个验证过程很重要,因为有些情况下FM虽然在日志里显示healthy,但实际fabric partition还没建立完整,只有通过一次真实的NVLS通信才能确认整个domain可用。

5.3 同步升级整个批次节点

修复单机只是起点。如果一个训练集群里有多台B200节点,必须把每台节点的驱动、FM、以及NVSwitch固件都同步到同一版本,否则后面跨节点多卡通信还会踩同样的坑。我们之后的处理是写了一个简单的批量检查脚本,在所有节点上跑一遍nvidia-smi和dpkg -l | grep fabricmanager,把结果打进表格,人工比对版本号,确认完全一致后才恢复训练任务。这步虽然琐碎,但能避免"这台好了,下一台又在半夜开始卡"的局面。

同时也要确认所有节点上的nvidia-fabricmanager服务都被设置为开机自启。因为FM是NVSwitch控制面,如果某台节点重启后没有自动拉起,整个fabric都会处于"不健康"状态,其他节点即使版本匹配,也会因为peer状态异常而无法建立跨节点的NVLS domain。

6. 避免下次再掉进同一类坑:几个硬件控制面排错经验

6.1 升级驱动时把FM和固件放入同一个变更单

很多多卡通信卡死都发生在驱动单独升级之后。驱动升了,FM还是老版本,或者FM升了,底层固件没跟上。建议把GPU driver、Fabric Manager、NVSwitch firmware这三样绑在一起做变更,尤其B200这种高密度板卡,不像普通显卡那样即插即用,升级控制面是整体动作。动驱动前先备份当前FM版本号,再制定回滚脚本,这样就算出了问题也能快速恢复。

这次故障就是因为之前一次驱动升级只更新了driver部分,FM包没有被一起更新,导致版本差了一个大版本。如果维护流程里能强制要求三者同步,这个故障根本不会发生。

6.2 建立一个FM健康度巡检脚本

经过这次排查,我习惯在每台节点上放一个脚本,定期检查FM版本和驱动版本是否匹配,出现异常直接告警。脚本逻辑不复杂:

  • 抓取nvidia-smi输出的driver version;
  • 抓取dpkg -l里FM包的版本;
  • 比对这两个版本是否属于同一个release分支;
  • 额外统计/var/log/fabricmanager.log中新的ERROR关键字。

对于超过50卡规模的机房,这类脚本性价比极高,能在故障扩散前提前发现问题。我们后来就是用这个脚本巡检了所有训练节点,顺利找出了另外两台存在同样隐患但还没爆发的机器。

6.3 不要忽略容器环境里的FM版本

如果你用容器跑训练(比如NVIDIA PyTorch容器),要注意:FM通常跑在宿主机上,但容器内的driver runtime和宿主机驱动版本要一致。有时宿主机FM是好的,但容器里挂载了不匹配的driver lib,一样会表现为NVLS异常。最好在容器里也执行一遍nvidia-smi --query-gpu=driver_version --format=csv,确保和宿主机输出的驱动版本对齐。

另外,容器里如果通过--privileged挂载了宿主机的一些库,比如libnvfm.so或libnvidia-nvswitch.so,也要注意这些库版本是否和宿主机的FM版本一致。不一致时,容器内程序可能感知不到FM的心跳,从而认为NVLS不可用。这一点在混用不同驱动版本镜像的团队里尤其容易踩。

讲了这么多,这次的体会其实就一句话:在NVSwitch平台上,多卡通信hang死不要急着怀疑硬件线缆,也不要花大把时间去调NCCL参数,先把FM和驱动版本一致性查了,十有八九能少走一天弯路。尤其是8×B200这种高密度板卡,控制面问题往往比数据面问题更致命,也更隐蔽。

RELATED READING

延伸阅读

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