凌晨两点,值班手机被一条“Mellanox 网卡光模块高温”告警震醒。这不是我第一次跟 NVIDIA Mellanox 网卡打交道,但那天之后,我下决心把自己负责的这套网络优化项目彻底工具化。我们内部给这个项目起名叫NEO,全称是Network Edge Optimization,其实做的事情很朴素:把节点上每一张 Mellanox ConnectX 网卡、每一根光模块/线缆的物理状态全部盘清楚,在 GPU 集群的“最后一公里”上减少莫名其妙的卡顿和断链。文章里要聊的mlxlink -d mlx5_9 -m/-c参数,就是我在这个项目里使用频率最高的两把螺丝刀。
如果你也负责跑 AI 训练集群、存储网络或者 HPC 高速互联,大概率会遇到类似的场景:nvidia-smi正常、RoCE ping 也通,但分布式训练一跑就时不时超时,最后抓破头皮才发现是某个光模块接收功率掉到了悬崖边上。下面这些内容,就是我基于实际排障经验整理出来的 NEO 项目实战笔记。
1. 项目代号 NEO 的由来:我们为什么盯上 Mellanox 网卡
1.1 从 GPU 集群的“最后一公里”说起
单张 GPU 卡的计算能力越来越猛,但跨节点的数据交换还是要靠网络。在我们机房里,一台 8 卡 GPU 服务器通常会配一张或两张 NVIDIA Mellanox ConnectX 系列网卡,通过 100G/200G 以太网或 InfiniBand 把数据送出节点。这套链路里面,最容易被忽略的就是节点出口那一段物理层——包括光模块、线缆、接口连接器和 PCIe 链路。
NEO 这个项目一开始并不叫 NEO。最早我们只是在监控脚本里加了一条ethtool -S收包错误统计,后来发现很多问题其实不在驱动、不在路由,而在光模块的发射光功率、接收光功率和温度。于是我们就把“节点出口物理层检查”单独列为一个项目,起名 NEO,也就是 Network Edge Optimization。项目刚启动的第一个月,就靠这几条命令在十几个节点里找出了三根有隐患的线缆和两个劣化光模块。
你可能会问,为什么不用交换机端去定位?交换机当然能看链路状态,但端到端的问题必须从两端各自的视角去看。同一个光纤回路上,A 端看到的是发送功率,B 端看到的是接收功率;如果 B 端接收功率不对,可能是光纤衰减、接头脏污,也可能是对端发射模块有问题。这时候单看交换机端口是不够的,必须站在每块网卡的视角去读模块诊断信息,这也是mlxlink这类工具无法被替代的原因。
1.2 选型:ConnectX-6/7 还是 BlueField?
NEO 的第一批节点选的是ConnectX-6 Dx双口 100G,后来扩容时也上过 ConnectX-7。为什么不直接全上 BlueField?因为我们的场景主要是 GPU 节点的 RoCE 通信,不需要把 Open vSwitch 卸载到 DPU 上,用 ConnectX 系列更简单、成本也更可控。如果你要做虚拟机网络卸载、裸金属云化或者更复杂的可编程数据处理,再考虑 BlueField 也不迟。
选型时还有一个容易忽略的因素:不同型号网卡对mlxlink的支持字段不完全一样。ConnectX-5 以前的部分网卡可能读不到完整的线缆信息,ConnectX-6/7 基本能覆盖常见的光模块和 DAC/AOC 线缆。我在 NEO 项目里踩到过一个坑:拿最新版 MFT 在旧型号 ConnectX-4 上执行mlxlink -c,工具直接报 “Command not supported”,最后还得回到ethtool -m去读模块信息。所以如果你照着本文的步骤操作,最好先确认一下手头设备的固件版本和 MFT 版本,别等到命令跑不通才回头查兼容性。
2. 环境准备:让 mlx5_9 出现在 mlxlink 的视野里
2.1 安装 MFT / mlx-tools 的注意事项
mlxlink不是 Linux 内核自带的工具,它通常随MFT(Mellanox Firmware Tools)一起发布。NVIDIA 官网的 Networking Software/Firmware 页面里可以下载对应操作系统版本的 MFT 包,安装后一般会提供mst、mlxlink、mlxup等一堆工具。
安装时最常见的坑是版本匹配。生产服务器如果跑的是 Ubuntu 20.04/22.04,且内核是定制过的,直接用官网的 MFT RPM/DEB 包通常没问题;但如果你自己编译过内核,最好先确认 MFT 包依赖的 kernel modules 能正常编译。另外一个更隐蔽的问题是:MFT 版本太旧,会导致mlxlink无法解析新固件的部分字段。比如某些 ConnectX-6 固件升级后,老版本 MFT 读出来的温度、电压全是 “Unknown”,而不是实际数值。所以,我会在每次升级网卡固件时顺手把 MFT 也升到对应版本,避免工具和固件鸡同鸭讲。
装完之后先跑一条命令确认设备树状态:
sudo mst start sudo mst status正常输出里能看到类似这样的设备列表:
DEVICE_TYPE MST PCI BUS IRQ ConnectX-6 Dx /dev/mst/mt4125_pciconf0 ...mst status里显示的设备路径是后续很多工具的输入,但mlxlink用的设备名不太一样,它直接接收mlx5_9这种内核设备名。
2.2 识别设备号:mlx5_9 到底是谁
第一次看到mlx5_9的人多半会懵:这是网卡型号吗?不是。mlx5_9是 Mellanox 驱动mlx5_core创建的设备实例名,数位序号一般来自系统对多张网卡/PF 的枚举顺序。同一台服务器里插了两张 ConnectX-6 和一张 ConnectX-4,很可能就会看到mlx5_0、mlx5_1、mlx5_2之类,序号完全由驱动加载时决定。
要弄清楚mlx5_9对应哪张物理卡、哪个网口,我的习惯是先看 lspci:
lspci -nn | grep -i mellanox然后把 RDMA 设备名和端口映射关系打出来:
ibstat ibdev2netdev比如输出可能是:
mlx5_9 port 1 ==> enp216s0np0 (ConnectX-6 Dx)这样我们就知道mlx5_9对应的物理网卡是哪一个了。多卡服务器上最怕的就是拿mlx5_9的诊断结果去拔另一张卡的线,所以在执行mlxlink之前,务必先把映射关系确认清楚。我们 NEO 项目里的巡检脚本,第一步就是自动跑ibdev2netdev生成一张网卡端口到mlx5_*的对照表,再逐个做诊断,不然拔错线真的会让整个训练队列中断。
3. -m 参数实战:光模块 EEPROM 与光功率读数全解
3.1 理解模块信息输出字段
当你确定要对某个设备做光模块诊断时,最常用的命令是:
mlxlink -d mlx5_9 -m-m在这里表示读取Module(模块)信息,也就是网卡上插着的那个 QSFP28/QSFP-DD/OSFP 光模块的 EEPROM 内容。Mellanox 网卡遵循 SFF-8636 类的管理接口规范,模块里会存厂商、型号、序列号、速率能力、波长,以及实时诊断数据。
我简化后的输出大致长这样:
Device : mlx5_9 Module ID : QSFP28 Type : 100G SR4 Vendor Name : Mellanox Part Number : MFA1A00-C003 Serial Number : MT1234X56789 Temperature : 51.0 C Vcc : 3.29 V Tx Power : 1.32 mW Rx Power : 0.85 mW Rx Power High Warn: 2.50 mW Rx Power Low Warn : 0.10 mW这些字段看起来多,实际排障时需要优先看三样:
- Temperature:模块内部温度,长时间超过 70℃ 要警惕;有些型号的告警阈值设在 75℃ 以上,但高温会加速模块劣化。
- Vcc:模块供电电压,正常在 3.13V-3.47V 之间。偏离太多可能不是模块坏了,而是主板供电或背板接触问题。
- Tx Power / Rx Power:发射功率和接收功率,这是判断链路质量最直接的证据。
拿到这些数据,先别急着高兴,还需要理解功率的单位和含义。mlxlink默认显示的mW只是毫瓦,很多资深网络工程师习惯用 dBm。换算很简单:dBm = 10 * log10(P / 1mW)。比如0.25 mW对应-6 dBm,1 mW对应0 dBm。
3.2 用光功率判断链路质量
光模块的发射功率一般集中在 1mW 上下(也就是 0 dBm 附近),100G SR4 光模块接收端能工作的最低功率一般在-8 dBm 到 -10 dBm左右,但这只是“能工作”的边界,不代表“稳定”。我通常会把 -6 dBm 作为观察阈值,低于这个值就进入重点跟踪名单;如果收到大量 CRC 错误再加接收功率掉到 -10 dBm 以下,基本上可以直接判断物理层在恶化。
举一个实际案例:有段时间某训练节点的 NCCL all_reduce 性能时好时坏,ibstat显示 LinkUp,但跑大规模集合通信时延迟偶尔飙高。我对着mlxlink -m的输出一看,Rx Power从正常时的0.6 mW掉到了0.04 mW,换算过来约 -14 dBm,这已经远超模块能稳定工作的范围。为什么链路还能 up?因为极低速率下信号还能恢复,但 100G PAM4 信号对噪声和幅度太敏感,瞬间就出 FEC 纠错风暴。更换模块后Rx Power回到0.7 mW,问题立刻消失。
这里要说一个容易误判的点:mlxlink -m读到的Rx Power是模块内部接收光功率,它低不一定是模块坏,也有可能是光纤连接头脏了、光纤弯曲过大、对端发射模块功率下降。所以看到 RX 低,我下一件事就是去对端机器上也跑一次mlxlink -m,看一下对端的 Tx Power。如果对端 Tx 正常而本端 Rx 低,大概率是光纤链路损耗大,优先做清洁和重新插拔;如果对端 Tx 本身就低,那就要换对端模块。
3.3 第三方模块与“Unsupported”的真相
NVIDIA Mellanox 网卡有一个让很多运维头疼的机制:固件里会校验光模块/线缆的厂商信息。如果你插了非 NVIDIA 认证的第三方模块,mlxlink -m里可能显示Vendor Name: Other或者直接标记为Unsupported。这不代表模块物理上立刻不能工作,网卡可能仍然能 Link Up,但固件会关闭一些高级诊断能力,或者干脆拒绝开启端口。
我们曾经贪便宜买过一批第三方 100G AOC 线缆,插上去能亮,但mlxlink -m的 EEPROM 里很多字段都是乱码,而且使用过程中出现过高频 CRC 错。后来和厂商确认,是因为他们的线缆 EEPROM 里写的告警阈值和 Mellanox 网卡预期不一致,导致网卡错误触发了一些保护逻辑。换回 NVIDIA 认证线缆后,一切正常。这条经验建议你记下来:在需要长期稳定运行的生产环境里,不要省那个模块/线缆的钱,认证兼容性本身是 SLA 的一部分。
4. -c 参数实战:线缆诊断与故障定位
4.1 DAC/AOC 线缆的信息读取
说完了光模块,再来说另一个高频场景:直连铜缆(DAC)和有源光缆(AOC)。这两种线缆的接口和光模块一样,但它们的“模块”是直接封装在线缆两端的。Mellanox 支持用mlxlink的-c参数读取线缆信息,命令长这样:
mlxlink -d mlx5_9 -c-c在我理解里对应的就是Cable(线缆)诊断/信息读取。它会读线缆内部的 EEPROM,给出线缆类型、长度、厂商、支持的速率,还有一些和信号质量相关的参数。输出示例:
Cable Type : Passive Copper Cable Length : 2m Vendor Name : Mellanox Part Number : MCS2A00-A002 Serial Number : ... Supported Speed : 100Gb/s Link State : ActiveDAC 线缆本身没有光功率,所以-m那些模块诊断字段在 DAC 上永远读不到,真正要关注的是线缆两端的连接状态、信号调整参数、以及有无异常告警位。AOC 线缆则把电光转换藏在两端,线缆 EEPROM 里会多出一些和激光器相关的状态,比如发射光功率、接收光功率,这些信息同样通过-c读取。
一开始我们 NEO 项目里只对光模块跑-m,后来发现有一批问题其实发生在 DAC 线缆上,才把-c也加进了巡检脚本。两者配合起来,基本上能覆盖服务器出端口的所有物理形态。
4.2 用 cable 信息定位瞬时断链
说一个用-c抓到“真凶”的案例。某个存储节点上的 100G 链路每隔六小时左右就会 flap 一次,时间点完全没有规律,系统日志里只能看到网卡端口 Link Down/Link Up。我第一次排查时怀疑是交换机配置问题,后来看了交换机日志,发现链路 down 的原因是远端信号丢失,并且发生时间点和节点本地网卡日志完全吻合。
于是走到服务器侧,先mlxlink -d mlx5_9 -c看了下这根线缆的状态,发现Link State: Active,但有一项Cable Warning: Out of Range亮着。继续往下翻,看到一个Cable Temperature字段明显偏离同批次其他线缆好几度,而且还有一组Signal Margin参数在多次采样里数值忽高忽低。后来把这根线缆搬到实验室压力测试,发现轻微弯折时信号余量会断崖式下跌。换线之后,问题彻底消失,六小时定时 flap 没有再出现过。
那次之后我学到一个经验:瞬时断链不一定都是模块坏,可能是线缆内部的物理损伤。DAC/AOC 一旦内部光纤或铜芯受力弯折,平时可能还能协商上,但温度变化或者震动就会让信号余量跌破阈值。mlxlink -c的价值在于把线缆的状态字段暴露出来,哪怕这些字段平时不会显示红色告警,也要纳入趋势记录。
4.3 链路协商参数的额外检查
除了线缆本身的信息,-c输出里通常还包括两端协商出来的工作速率、FEC 模式、自动协商状态。这些参数和物理层问题交织在一起,如果只盯着光模块功率,往往会漏掉真正的原因。
比如 100G 以太网通常建议开启 RS-FEC(Reed-Solomon FEC),因为 PAM4 信号对噪声敏感,不开启 FEC 的话,短距离光模块都可能出现几百个 CRC 错误。但如果两端协商时不匹配——一端开 RS-FEC,另一端只开 FC-FEC 或者关掉 FEC,表现就是链路能起来,但 FEC 错误计数器一路猛涨,业务性能却拉胯。
用mlxlink -d mlx5_9 -c看当前协商结果,确认两端 FEC 模式一致,是排查这类问题的第一步。如果发现不一致,别急着敲命令强制配置,先查交换机端口的配置:很多交换机默认对 100G 端口启用 RS-FEC,而服务器网卡默认配置可能没有,你需要在两端找到共同可接受的配置再统一调整。
5. 现场排错:一次 mlxlink 定位光模块劣化的完整链路
5.1 现象:业务报错与链路反复 flap
NEO 项目上线后,遇到最典型的一次问题是某个训练集群频繁出现 NCCL 超时。表面现象非常具有迷惑性:
- 所有网卡
nvidia-smi正常,GPU 利用率高的节点跑单机测试没问题; - RoCE ping 能通,
ibstat显示端口状态为 Active; - 但一旦跑大规模 all_reduce,偶尔会有人报 “Timeout”;
- 边缘交换机上看端口没有长时间完全 down,但 FEC 错误计数器在跳跃。
这种问题最怕“看起来都正常”。如果没有物理层工具,我们大概率会陷入反复调整 NCCL 超时参数、修改路由、重装驱动的泥潭。实际上,分布式训练对网络质量的敏感度远高于普通 TCP 业务,微小的物理层抖动都会被集合通信放大。
5.2 排查:把可疑网卡按序号捋一遍
我先把集群里所有 GPU 节点的 Mellanox 网卡设备名梳理出来,用ibdev2netdev拿到mlx5_*到网口的映射,然后写了一个小循环,挨个执行:
for dev in $(ibstat -l); do echo "== $dev ==" mlxlink -d "$dev" -m | grep -E "Temperature|Tx Power|Rx Power" done这个脚本在几十个节点上跑完后,只有mlx5_9的Rx Power明显异常,而且温度也偏高。再回头看这台节点的机柜位置,发现它正好在空调出风口对面,但挡板前堆了一堆标签线缆,散热条件很差。到这里,已经基本锁定是两个因素叠加:模块本身可能有老化,环境温度又加快了劣化速度。
接着我用mlxlink -d mlx5_9 -m连续采了 10 次数值,发现Rx Power在-13 dBm到-15 dBm之间波动。按我们 NEO 项目的判定标准,这类模块必须直接更换,不能再等了。
5.3 结论与替换方案
最后我们联系硬件厂商更换了那个光模块,顺便整理了挡板前的理线,让模块进风更顺畅。替换后mlxlink输出的关键数值恢复正常:
| 指标 | 异常时 | 更换后 |
|---|---|---|
| Temperature | 71.5 ℃ | 48.0 ℃ |
| Tx Power | 0.9 mW | 1.3 mW |
| Rx Power | 0.04 mW | 0.72 mW |
新的模块连续跑了一周,FEC 错误计数清零,NCCL 也不再出现超时。这次排障让我更加坚定:NEO 这种项目不能只看端口 up/down,必须把物理层诊断数据纳入日常巡检。哪怕一个月只捡出一根有隐患的线缆,也值回工具学习和脚本开发的成本。
6. 那些文档里不会写的坑:散热、兼容性与固件版本
6.1 模块温度与散热口的关系
很多运维第一次看到光模块温度上 70℃ 都以为模块坏了,其实未必。光模块的散热路径非常短,它插在网卡面板里,热量主要靠机箱风流带走。如果机柜前后挡板被杂乱的线缆堵住,或者服务器前脸正好被隔壁设备的电源吹出热风干扰,模块温度能轻松比正常高 10℃。
我在 NEO 巡检脚本里给温度加了两个阈值:65℃ 时报警,60℃ 以下才认为正常。高温环境下,光模块的激光器发射效率会漂移,长期下来接收灵敏度下降,最终出现那种“时好时坏”的链路。如果你用mlxlink -m看到温度高,先别急着换模块,看看物理环境;把散热改好之后温度恢复正常,往往模块还能继续用很久。
6.2 固件版本和 MFT 版本要一起升
Mellanox 网卡的固件升级工具是mlxup,但很多人不知道,mlxlink的字段解析能力和固件版本、MFT 版本都有关系。我遇到过同类网卡,一台机器上mlxlink -m能正常读功率,另一台上干脆报 “Failed to get module info”,最后发现是那台机器的 MFT 没升级,和已经升级的固件不兼容。所以在 NEO 项目里,我要求所有节点必须保证 MFT 版本和网卡固件版本同批次升级,不要拆分操作。
顺带提一句,如果你在 Ubuntu 上折腾过 NVIDIA 驱动,应该体会过“驱动模块和内核版本不匹配”的酸爽。Mellanox 的 OFED 驱动和 GPU 的 NVIDIA 驱动是一对容易互相踩踏的邻居,尤其是系统自动更新内核后,mlx5_core和nvidia模块经常一起罢工,还会连带出现类似nvidia-smi has failed because it couldn't communicate with the nvidia driver的报错。这时候先别怪驱动,去看一下自己是不是升级内核后忘了重新安装 OFED 和 NVIDIA 驱动。把系统更新纳入变更管理,比事后排队重装要省心得多。
6.3 其他实用命令组合
除了-m/-c两个参数,NEO 项目里的日常巡检还会用到几个互补命令:
mlxlink -d mlx5_9 -e:查看以太网端口统计,包括 CRC、FEC 错误;ethtool -m enp216s0np0:有时 MFT 装不了或者版本太老,ethtool -m也能读出一部分模块 EEPROM;mst status:快速确认设备是否被驱动识别;ibstat:确认 InfiniBand/RoCE 端口状态。
组合起来,我通常会在巡检脚本里先跑mst status,再对每个mlx5_*执行mlxlink -m和mlxlink -c,把结果以 CSV 存起来,按天拉趋势。判断标准很简单:接收功率不能连续两天下降超过 1 dB,温度不能持续高于 65℃。一旦达到报警条件,值班人员会主动找硬件厂商处理,而不是等到分布式训练报错再生产变更。
这整套流程,就是 NEO 项目给我的最大回报:把不可见的物理层风险,变成每天可见的量化趋势。最后再分享一个小技巧:mlxlink -c在不同固件版本上输出的字段名略有差别,有些老版本叫Signal Integrity,新版本可能改成SNR Margin,别看到 Unknown 就紧张,先 grep 一把同批所有设备的数据,如果所有设备都是 Unknown,大概率是工具版本问题,而不是硬件真的坏了。