一、案发现场:风扇在转,BMC 说它没转
深夜,一台跑了七年的 4U GPU 服务器在告警日志里刷”风扇转速过低”。走过去一看:被点名的中置风扇,转得好好的,风也在出。第一反应自然浮现——转速传感器间歇性失灵,风扇转它的,传感器报它的,各说各话。
这台机器是曙光贴牌的超微 SYS-7048GR-TR(X10DRG-Q 主板、SC747 机箱),机箱中置一排 8 颗 8cm 高静压风扇,由 BMC 统一监控。被点名的是风扇墙上的一颗,通道名 FANA。
这个”传感器失灵”的假设,后来被证明方向对了一半——失灵的确实是转速信号,但坏的不是风扇里的传感器。
二、第一坑:台架复测,差点冤案定性
标准操作:把风扇拔下来,接到台式机主板的风扇口上读转速。读数出来了,但是锯齿——1400 到 3300 RPM 来回跳,还伴随可闻的转速波动。差点当场定罪:”读数这么乱,传感器确实失灵。”
幸好多想了一步:服务器风扇(电流 ≥2A)挂在台式机主板风扇口(供电能力 ~1A)上,本就欠压;台式机温控曲线还在动态调压。读数锯齿里有相当一部分是”供电+调速”混入的噪声。台架能证明”风扇会转”,既不能证明传感器没问题,更不能证明它有问题。
教训一:换了环境就换了变量。台架只适合定性(会转/不会转),不适合定量定罪。
三、转机:BMC SEL 是金标准
回到正主。BMC 里有一份带时间戳、读数值和阈值的事件日志(SEL,System Event Log),风扇每一次”转速过低/恢复”都有记录。从另一台机器用 ipmitool 走 IPMI over LAN 读取:
ipmitool -I lanplus -H <BMC_IP> -U <user> -P <pass> sel elist
两个发现:
- SEL 已经 512/512 满,被同一个通道(FANA)的告警刷爆——86 条,其中 42 次”Reading 0 < 100 RPM"断言;
- 告警形态:转速读数掉到 0,几秒后恢复,恢复值从 200 直接跳到 4700(1 秒内),中间没有任何渐升。
物理上,一颗 4700 转的风扇不可能 1 秒内从 0 爬回 4700——中间必然经过 2000、3000。“0 → 瞬间恢复高速”(无渐升)= 转速信号丢失;恢复值渐升 = 真实停转。这条形态学判据直接把”风扇真的间歇停转”排除,把”转速信号间歇丢失”坐实。
(先卖个关子:信号丢失 ≠ 传感器坏。坏在哪,后面才知道。)
四、对调测试:让嫌疑犯和正常人换座位
台架的教训是”单点读数不可靠”,那就上刑侦剧的经典桥段——对调。找一颗确认良好的风扇,和 FANA 上的嫌疑扇互换位置。
结果:好风扇放到 FANA 上,照样读 0。
故障不在风扇,在通道——主板侧从 FANA 针脚到传感器芯片之间,某处间歇性断路。最初”传感器失灵”的怀疑,方向对了一半:失灵的确实是转速信号,但坏的不是风扇里的那个,是主板收信号的那一段。
五、时间线考古:告警全部跟着”开箱”走
SEL 是满的,更早的事件已被滚动冲掉,但保留的 512 条里有别的线索。把全部机箱开启(Chassis Intrusion)事件和风扇告警放到同一条时间线上:
| 日期 | 开箱记录 | 风扇告警 | 间隔 |
|---|---|---|---|
| 07-12 | 19:32 开箱 | 20:38 FANC、20:39 FAN3(各一次) | 约 1 小时 |
| 07-13 | 多次开箱 | 04:50 FAND(一次) | 跨夜 |
| 09-21 | 06:50 开箱 | 06:52 FANA 告警 | 2 分钟 |
| 10-06 | 00:11 开箱 | 00:43 FANA 爆发(44 条) | 32 分钟 |
| 08-19 ~ 09-17 | 无开箱 | 零告警 | — |
每一次风扇”发病”,都发生在有人动过机箱之后;一个月没动机箱,风平浪静。结论收敛:物理扰动触发——针脚虚焊或接插件氧化,振动与温度变化让接触忽通忽断。焊点级的病,软件治不了,但软件可以不让它骗人(第七节)。
六、软件三坑:每一个都消耗了一小时以上
排查期间顺手把这台机器的风扇软件控制摸了个透,三个坑值得单独记:
坑 1:ipmitool raw 的参数按十六进制解析
设置风扇占空比的 raw 命令,最后一个参数是百分比。我传 35,风扇跑在 3600 RPM 不动——因为 ipmitool 把它读成 0x35 = 53%。十进制的 35 要写成 23(0x23)。一位数的 5 碰巧十进制等于十六进制,所以”看起来对”。所有 raw 命令的数值参数都要过一遍 HEX 换算。
坑 2:远程写占空比会被固件”假接受”
从另一台机器用 -I lanplus 远程写占空比,命令返回成功,风扇纹丝不动。只有在服务器本地(KCS 总线,sudo ipmitool raw ...)写入才真正生效。这台 AMI/ATEN 固件对网络来源的写命令是”礼貌性点头”。调试时要先认清哪条通道是真通路。
坑 3:BMC 保护态——风扇缺失会锁死手动控制
把机箱扇全部拔掉后(8 个通道报 0),BMC 进入保护态:即使切到 Full 模式,区占空比写入也被无视,在位的风扇(CPU 散热器风扇)被钉在保护转速 ~3600 RPM。反复写不但无效,还会让风扇每写一次抖一下。
保护态本身是合理设计(风扇大面积缺失时不允许人为压低转速),但要知道它的存在——它会让你的所有手动调速实验静默失败。识别方法:写 100%,看转速响应。
七、GPU 涡轮:NVML 手动控制与”缓升陷阱”
两块 GPU(一张专业卡、一张消费卡)的涡轮风扇都可以通过 NVML 手动调速(pynvml + sudo,headless 服务器不需要 X 和 Coolbits):
import pynvml
pynvml.nvmlInit()
h = pynvml.nvmlDeviceGetHandleByIndex(0)
pynvml.nvmlDeviceSetFanControlPolicy(h, 0, 1) # 1 = MANUAL
pynvml.nvmlDeviceSetFanSpeed_v2(h, 0, 45) # 45%
两个坑:
- 缓升特性:专业卡的涡轮从 30% 拉到 45%,实际转速以 ~2–3%/秒爬升,约 10 秒收敛。第一版测试设完 2 秒就读数、读完就恢复自动——结论”固件锁死手动控制”。错。测试要等收敛,还要同时读 Target 值对照(target 跟了命令 = 接受;actual 慢慢爬 = 只是在路上)。
- 命令 40%、实际 46%:卡片有最低占空比/执行偏差,写脚本时按实测标定。
八、终局:拆掉机箱扇,让该转的转,让软件守夜
FANA 的焊点病既然是硬件级的,短期方案就是绕开:把 8 颗机箱扇全部拔掉(BMC 进入保护态,机箱扇区静音),保留 CPU 散热器风扇(保护转速固定、安全)和 GPU 涡轮(软件可控),再写一个温度守卫服务:
- 每 5 秒读 7 路温度 + 全部风扇转速,写 CSV;
- 默认只监控;任一传感器 ≥75°C:接管双卡涡轮,按温度梯度 35/60/85/100% 拉速(带”棘轮”——接管值永不低于当前实际转速,避免接管反而降速);
- ≥88°C 持续 15 秒且涡轮已满速:系统层降负载——GPU 功率墙降到 60%、CPU 频率上限 50%;
- 全部回落 65°C 以下:解除降载,涡轮交还自动。
然后跑了一次真实负载:单卡 LLM 推理,满载 180W 十分钟。峰值 63°C(离接管线还有 12 度),机箱内温升 3 度,守卫全程静默——这个”拆掉 8 颗机箱扇、只留精准散热”的形态,扛住了真实推理负载。代价也说清楚:VRM 和内存没有专门风道,双卡满载长跑需要盯温度;机箱敞开防尘靠自觉。
九、方法论小结(可复用的五条)
- BMC SEL 是风扇故障的金标准:时间戳+读数值+阈值,比任何台架都可信;
- 形态学判据:0→瞬间恢复高速(无渐升)= 信号丢失;恢复值渐升 = 真实停转;
- 对调测试优于一切单点读数——让嫌疑犯和正常人换座位;
- 告警时间线 vs 物理操作记录交叉:如果”发病”总跟着开箱走,方向就是接触/焊点;
- 改完软件要重启进程——所有”灵异现象”里,一半是旧进程在跑旧代码。
尾声
FANA 的虚焊还没修——那是”安静模式”和”全功能模式”之间的那道门,修好它需要把主板拆下来补焊。在那之前,这台机就以”8 缺 8″的形态安静地跑着:该转的转,该守的守,凌晨的机房里只有 GPU 涡轮轻微的风声。
FANA 的虚焊还没修——那是”安静模式”和”全功能模式”之间的那道门。
说起来,这是整个排查里最传奇的一幕:FANA 以一人之力——确切说,以一枚虚焊的针脚——带着其他 7 个风扇兄弟,集体休假去了。它的转速信号一丢,告警把所有人折腾了个遍;折腾到最后,整面风扇墙干脆被拔下来,躺进了防静电袋。机器以”8 缺 8″的形态安静地跑着,站岗的只剩两颗 CPU 散热器风扇和两颗 GPU 涡轮——该转的转,该守的守,凌晨的机房里只有涡轮轻微的风声。
至于那颗被冤枉了半个月、后来又带队出走的风扇——它现在终于可以理直气壮地不转了。等主板的焊点补好,它随时带着兄弟们回来上班。