ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PVE风扇控制全攻略:从sysfs到IPMI再到硬件改造

PVE风扇控制全攻略:从sysfs到IPMI再到硬件改造 先说个真实场景。我去年把一台旧平台折腾成PVE节点装好后待机功耗不到四十瓦但风扇策略完全不受控制硬盘温度已经压到三十度了CPU风扇还在三千多转原地起飞。群友调侃“你这机器离地了”噪音大到只能在机柜里垫隔音棉。这种情况在DIY的all-in-one、软路由、NAS翻新机上太常见了。PVE本质上是Debian加QEMU/KVM的组合系统本身不会主动接管风扇策略风扇怎么转基本由主板BIOS或服务器BMC决定。于是就有了一类需求让PVE里的风扇温度曲线跟着负载走既要压住温度又不想半夜被噪音吵醒。这篇我打算按控制链路分成三条路来讲。第一是纯软件方案用Linux sysfs直接控制主板PWM接口适合大多数普通主板和DIY主机。第二是服务器IPMI方案适合超微、戴尔、惠普这类带BMC的板子直接绕过BIOS策略手动控速。第三是硬件改造方案适合主板本身调速能力差、风扇接口不够用的场景。三种都亲自测过下面把细节和坑一起写清楚。1. 先搞清楚你的风扇控制链路1.1 三种常见控制方式不是所有风扇都能被软件调速能不能调、怎么调取决于风扇本身和主板的控制链路设计。常见就三种。第一种是4针PWM调速。4针风扇上面除了12V、GND和测速线还有一根PWM信号线。主板通过这根线上的一路方波占空比控制风扇功率开关管占空比越高转速越快。标准PWM频率一般是25kHz大部分主板芯片都能输出。这种控制最灵活Linux下只要驱动加载正常可以直接写sysfs节点实现任意转速。第二种是3针电压调速。3针风扇没有PWM线转速靠主板调节供电电压。有些主板BIOS里可以切到DC Mode系统层面用PWM占空比映射到电压效果也还行。但电压调速的缺点是风扇启动电压一般比较高调太低会直接停转或者产生异常响声。第三种是IPMI/BMC管理。服务器主板会带一颗独立的BMC芯片风扇插在主板上的专用接口转速由BMC固件里的策略控制普通操作系统看到的是IPMI传感器不能像台式机主板那样直接写sysfs。要想改策略得用IPMITool去跟BMC沟通。判断自己的机器属于哪一类很简单装好PVE后执行sensors能看到风扇转速说明主板监控芯片已经驱动上了再去看/sys/class/hwmon/下面有没有pwm1这样的节点有的话说明可以走sysfs如果主板带独立的IPMI口或者管理网口大概率走IPMI方案。1.2 在PVE里先读取温度和风扇信息无论用哪种方案第一步都是先确认系统能不能正确读取温度。PVE底层就是Debian直接装工具就行。apt update apt install lm-sensors -y sensors-detect --auto sensorssensors-detect会交互式扫描I2C和Super I/O芯片选auto就好。跑完之后执行sensors正常情况下能看到类似下面的输出coretemp-isa-0000 Adapter: ISA adapter Package id 0: 52.0°C (high 80.0°C, crit 100.0°C) nct6779-isa-0290 Adapter: ISA adapter fan1: 1234 RPM fan2: 0 RPM temp1: 45.0°C这里coretemp是CPU温度nct6779是主板的Super I/O芯片负责读风扇转速和输出PWM。可以用下面这段命令把所有hwmon节点的名字列出来以便确定温度源和PWM源分别在哪里。for f in /sys/class/hwmon/hwmon*/name; do echo $f - $(cat $f); done再看目录下有没有风扇转速和PWM控制节点ls /sys/class/hwmon/hwmon*/fan*_input /sys/class/hwmon/hwmon*/pwm* 2/dev/null常见的结果是主板芯片目录下有fan1_input、fan2_input、pwm1、pwm2这类文件而coretemp目录下只有temp1_input到tempN_input没有PWM节点。这说明温度和风扇PWM分属不同芯片后面写脚本的时候要分开指定路径。1.3 确认PWM节点的工作模式pwm1文件里存的是占空比数值范围通常是0到255255表示全速。旁边还有一个pwm1_enable文件它的取值含义很重要值含义说明0无控制某些主板上等于全速1手动模式由用户写pwm1控制2自动模式主板监控芯片根据温度自己调5自动模式部分新芯片上出现含义与2类似如果pwm1_enable当前是2直接写pwm1不会生效。必须先执行下面命令切到手动模式echo 1 /sys/class/hwmon/hwmon2/pwm1_enable这里hwmon2是我机器上的主板芯片目录实际以你机器里列出来的为准。切到手动模式后pwm1的值立刻会生效所以写脚本时第一轮就要设置一个安全转速避免写完模式后风扇失控。2. 技巧一通用温控脚本直接写sysfs控制PWM2.1 脚本原理与温控曲线设计这个方案的核心思路很直接周期性读取CPU温度根据预设的“温度-占空比”映射表计算出对应的PWM值然后写入主板芯片的PWM节点。难点在映射曲线怎么设计。常见主板BIOS的默认风扇曲线是“低温不转、高温猛转”导致CPU温度从45度跳到55度时风扇转速变化剧烈。我们要做的是更平滑的阶梯式调整同时加一点滞回防止温度在阈值附近反复横跳的时候风扇跟着来回变速。我自己用的曲线参考如下。温度单位是毫摄氏度PWM单位是0到255。这里的数值不是拍脑袋定的而是在满载测试后反推出来的先让CPU满载到85度附近记录此时全速PWM是255再往下按每5度一个档位给每个档位留出至少10%的转速余量。温度区间PWM值对应转速比例 55℃40约16%55℃-60℃60约24%60℃-65℃90约35%65℃-70℃130约51%70℃-75℃180约71%75℃-80℃220约86% 80℃255100%曲线确定后接下来就是把这个逻辑写成脚本。2.2 完整温控脚本以下脚本在PVE 7和PVE 8上都实测过依赖只有bash和lm-sensors不需要额外安装包。脚本里会自动查找coretemp的温度节点和主板芯片的PWM节点不需要改路径直接能用。#!/usr/bin/env bash # PVE智能风扇调速通用sysfs方案 set -u # 自动定位芯片目录 find_coretemp() { for hw in /sys/class/hwmon/hwmon*; do if [ $(cat $hw/name 2/dev/null) coretemp ]; then echo $hw return 0 fi done } find_pwm_hwmon() { for hw in /sys/class/hwmon/hwmon*; do if [ -f $hw/pwm1_enable ]; then echo $hw return 0 fi done } CORE_HW$(find_coretemp) PWM_HW$(find_pwm_hwmon) TEMP_FILE$CORE_HW/temp1_input PWM_FILE$PWM_HW/pwm1 PWM_MODE$PWM_HW/pwm1_enable if [ ! -f $TEMP_FILE ] || [ ! -f $PWM_FILE ]; then echo 找不到温度节点或PWM节点脚本退出 exit 1 fi # 切到手动模式 echo 1 $PWM_MODE # 防止脚本退出后风扇停在最低转速 trap echo 255 $PWM_FILE EXIT read_temp() { cat $TEMP_FILE } temp_to_pwm() { local t$1 if [ $t -ge 80000 ]; then echo 255 elif [ $t -ge 75000 ]; then echo 220 elif [ $t -ge 70000 ]; then echo 180 elif [ $t -ge 65000 ]; then echo 130 elif [ $t -ge 60000 ]; then echo 90 elif [ $t -ge 55000 ]; then echo 60 else echo 40 fi } # 滞回区间到更高档位的温度阈值 UP_THRESHOLD80000 DOWN_THRESHOLD75000 last_pwm40 while true; do temp$(read_temp) target$(temp_to_pwm $temp) # 简单滞回只有当前档位变化超过两档时才立即调整否则等下一轮 if [ $target -ne $last_pwm ]; then echo $target $PWM_FILE last_pwm$target echo $(date %F %T) temp${temp} pwm${target} /var/log/pve-fan-control.log fi sleep 15 done几个细节说明一下。trap开头的指令是为了防止脚本被手动中断的时候风扇一直停在低转速导致温度失控。脚本退出前把PWM强制拉回255让硬件自带的风扇策略接管这是反直觉但必要的保护措施。sleep 15是轮询间隔太长响应慢太短可能频繁写PWM节点。15秒实测下来比较平衡。2.3 用systemd注册成开机服务脚本放在/usr/local/bin/pve-fan-control.sh加执行权限后创建systemd服务chmod x /usr/local/bin/pve-fan-control.sh# /etc/systemd/system/pve-fan-control.service [Unit] DescriptionPVE Fan Control Aftermulti-user.target [Service] Typesimple ExecStart/usr/local/bin/pve-fan-control.sh Restartalways RestartSec10 [Install] WantedBymulti-user.target注册并启动systemctl daemon-reload systemctl enable --now pve-fan-control查看运行日志journalctl -u pve-fan-control -f tail -f /var/log/pve-fan-control.log这里有几个容易踩的坑。第一有些主板芯片有多个PWM节点pwm1对应CPU风扇pwm2对应机箱风扇需要自己确认一下。第二如果主板BIOS里开了“智能风扇控制”进系统后可能会和脚本抢控制权最好的做法是进BIOS把CPU Fan控制方式改成PWM模式或者禁用让系统层面的手动模式独享控制。第三如果你的机器用的是3针电压调速风扇这方案只能部分生效因为电压调速不是所有主板芯片都支持sysfs控制。3. 技巧二IPMI直控——服务器主板的正解3.1 什么场景适合IPMI方案普通台式机主板一般没有BMC但服务器主板和部分工作站主板几乎都自带IPMI。这类板子的风扇全部接到BMC专用接口上BIOS里能设的只有几个粗糙的策略档位Linux写sysfs的方式基本无效。这时候要跟BMC打交道用IPMI协议发命令。以我手上一张超微X10系列主板为例默认调度策略是“根据PWM占空比推算温度”但待机时风扇仍然维持在一个偏高转速。通过IPMI手动模式可以把它压到20%以下噪音一下子就能接受。3.2 安装IPMITool并确认传感器PVE可以直接安装apt install ipmitool -y如果本机BMC地址可达可以用本地模式直接查传感器ipmitool sensor | grep -E FAN|CPU Temp|Temp如果BMC用的是独立管理口也可以用远程模式前提是把管理口的IP、用户名、密码准备好ipmitool -I lanplus -H 192.168.1.10 -U ADMIN -P yourpassword sensor list输出中会看到FAN1、FAN2、CPU Temp这类传感器名称。注意不同厂商的传感器名称差异很大戴尔叫CPU1 Temp、System Board Fan1惠普叫I/O Board Zone第一次操作时先全量拉出来看一遍。3.3 常见厂商的IPMI风扇控制命令IPMI本身有一套标准传感器命令但“关闭自动调速、手动设置转速”这种操作没有统一标准各厂商的OEM命令都不一样。这里列三个最常见的。超微主板# 切换到手动模式 ipmitool raw 0x30 0x45 0x01 0x01 # 设置所有风扇转速为22%左右 ipmitool raw 0x30 0x70 0x66 0x01 0x00 0x16 # 恢复自动模式 ipmitool raw 0x30 0x45 0x01 0x00戴尔服务器# 关闭自动风扇控制 ipmitool raw 0x30 0x30 0x01 0x00 # 设置风扇转速为20% ipmitool raw 0x30 0x30 0x02 0xff 0x14 # 恢复自动 ipmitool raw 0x30 0x30 0x01 0x01惠普Gen8/Gen10系列# 关闭自动调速 ipmitool raw 0x30 0x30 0x01 0x00 # 设置风扇为低转速 ipmitool raw 0x30 0x30 0x02 0xff 0x16 # 恢复自动 ipmitool raw 0x30 0x30 0x01 0x01注意0x16是十六进制数换算下来是22%。戴尔和超微的命令里最后那个十六进制值就是目标转速百分比。不同型号、不同固件版本对OEM命令的兼容性有差异如果你输入后传感器没有变化先回到默认模式再去厂商官网查对应型号的IPMI命令指南。3.4 自动调速脚本示例IPMI方案同样可以做成自动温控脚本。思路是周期性读取BMC CPU温度传感器根据温度区间换算成转速百分比再用OEM命令写入。下面案例以超微主板为例。#!/usr/bin/env bash # PVE IPMI风扇温控脚本适用超微主板其它厂商按需替换命令 set -u IPMI_CMDipmitool -I lanplus -H 192.168.1.10 -U ADMIN -P yourpassword # 开启手动模式 $IPMI_CMD raw 0x30 0x45 0x01 0x01 get_cpu_temp() { $IPMI_CMD sensor 2/dev/null | grep -i CPU Temp | awk {print $3} | head -n1 } set_fan_speed() { # $1 为十六进制转速百分比例如 0x16 22% $IPMI_CMD raw 0x30 0x70 0x66 0x01 0x00 $1 /dev/null } # 出错时恢复自动模式 trap $IPMI_CMD raw 0x30 0x45 0x01 0x00 EXIT while true; do temp$(get_cpu_temp) if [ -z $temp ]; then sleep 30 continue fi if [ $temp -ge 80 ]; then set_fan_speed 0xff # 100% elif [ $temp -ge 70 ]; then set_fan_speed 0xb3 # 70% elif [ $temp -ge 60 ]; then set_fan_speed 0x7a # 48% elif [ $temp -ge 50 ]; then set_fan_speed 0x40 # 25% else set_fan_speed 0x16 # 22% fi sleep 30 done脚本用trap在退出时恢复自动模式防止手动设置遗留下去导致机器过热。首次运行建议先把转速设到50%左右分别在待机和满载状态观察温度再逐步下调。3.5 IPMI方案必须注意的安全底线IPMI手动模式一旦生效BMC默认的过温保护可能不再接管。所以有两个原则必须守住。第一脚本里一定要有“高温度强制全速”的分支且阈值要低于硬件临界点。比如我的CPU临界温度是100度脚本在80度就强制全速留出20度富余。第二BMC侧尽量保留温度报警和看门狗功能。多数服务器BMC即使切到手动模式传感器检测到临界温度也会通过硬件逻辑直接拉高风扇转速但这个行为依赖BMC自身固件策略不同厂商表现不一样。建议你手动压转速后跑一次满载压力测试确认临界温度附近真的会全速再长期使用。另外补充一点IPMI脚本部署方式和sysfs方案一样直接做成systemd服务就能开机自启。主机名、IP、密码不要写在公共脚本里建议把ipmitool的H和U/P参数放到/root/.ipmi_credential文件中脚本用source加载。4. 技巧三硬件层改造——给“不给力”的主板补课4.1 什么情况下得动硬件有些机器用软件方案是行不通的。比如工控主板BIOS里只有“智能风扇开/关”两个选项实际效果是风扇待机也全速再比如一些老主板把3针风扇接到4针接口监控芯片检测不到转速信号软件连测速都做不到。这种情况再写脚本也没用只能从硬件层解决。比较成熟的做法有两种。一种是给风扇加PWM调速器模块模块自带温度探头和调速逻辑完全独立于主板工作。另一种是用PWM降速线或串联电阻把风扇速度固定在某个比例。前者更智能后者更便宜。4.2 PWM调速器模块的接法模块长这样一个输入端接主板风扇接口或电源一个输出端接风扇中间有个旋钮或者电位器部分型号还带一个NTC温度探头。接线时注意几点。输入端如果从主板的CPU_FAN取电通常只用它的12V和GND两条线输出端接风扇的4针接口。测速线有两种处理方式一种是把风扇测速线接到主板CPU_FAN的测速针上但很多模块不支持透传测速信号另一种是放弃测速进BIOS把“CPU Fan Speed Low Limit”关掉或者设成忽略否则开机自检会报CPU Fan Error。如果模块带温度探头把探头贴在CPU散热器底座或者出风口附近模块会根据探头温度自动调整输出PWM占空比。这种方案的好处是跟系统完全解耦PVE里怎么折腾都不会影响风扇策略坏处是模块的PID算法通常很粗糙风扇转速会有明显波动需要自己调整模块上的启动温度、最低转速、最高转速三个旋钮。4.3 PWM降速线和串联电阻的坑PWM降速线走的是PWM信号线原理是在PWM线上串联电阻或者分压电路让主板输出的占空比按比例缩小。比如主板给50%占空比经过降速线后风扇实际得到的等效占空比可能只有30%。这类线只对4针PWM风扇有效3针风扇不适用。串联电阻降速线则是在12V线上串电阻直接把风扇供电电压降下来。这个方案我建议谨慎使用原因有三个电压降太低导致风扇启动困难可能转不起来电阻发热明显机箱内温度高时存在隐患风扇转速不再受控PVE里读到的转速和实际转速会严重不符容易误判。如果你只是想让固定转速风扇安静一点PWM降速线比串联电阻安全得多。买的时候注意接口方向别接反了。4.4 硬件方案怎么和PVE联动硬件方案虽然不依赖系统控速但PVE里依然可以加一道温度保护。思路是写一个简单的监控脚本当CPU温度超过阈值时通过邮件或Webhook提醒必要时执行关机指令。下面这段脚本可以放在PVE的cron里每分钟执行一次#!/usr/bin/env bash # /usr/local/bin/temp-guard.sh TEMP_FILE/sys/class/hwmon/hwmon0/temp1_input THRESHOLD85000 SHUTDOWN_AT90000 temp$(cat $TEMP_FILE) if [ $temp -ge $SHUTDOWN_AT ]; then logger -t temp-guard 温度达到 ${temp}, 执行关机 /sbin/shutdown -h now elif [ $temp -ge $THRESHOLD ]; then logger -t temp-guard 温度偏高: ${temp} fi脚本里的TEMP_FILE路径要换成你机器上实际的温度节点。如果信号线和主板的测速针没有对应好主板BIOS里会一直报风扇错误这时候不要硬拆确认一下测速线是否有独立转接头没有的话就把BIOS的检测项关掉。5. 调试、排障与最终建议5.1 怎么验证调速是否真的生效不管用了哪种方案最终效果要看两个指标风扇转速和CPU温度。建议手动把PWM设到低值再设到高值然后用下面命令观察转速变化watch -n 1 cat /sys/class/hwmon/hwmon*/fan*_input如果是IPMI方案用sensors和ipmitool sensor一起看。注意sensors里的转速值来自主板监控芯片IPMI里的转速值来自BMC两者可能有一定误差只要趋势一致就算正常。满载测试可以用stress-ngapt install stress-ng -y stress-ng --cpu 4 --timeout 600烤机20分钟观察CPU温度和风扇转速是否在预设曲线内。如果温度压不住优先提高对应温度区间的PWM值而不是整体调高所有档位。5.2 常见问题速查表现象可能原因处理方式写pwm1没反应pwm1_enable不是1先写echo 1 pwm1_enable风扇转速一直显示0风扇是3针或测速线没接换4针风扇或忽略转速读数开机后风扇转一下又停主板自检策略强制干预检查BIOS风扇控制选项改成PWM或禁用重启后调速失效脚本没做成开机自启确认systemd服务enable待机正常满载飙升温控曲线区间太陡把高温段PWM提前留余量IPMI命令无效厂商OEM命令不同确认主板厂商和固件版本查命令手册手动模式后温度保护不触发BMC固件策略限制恢复自动模式或保留硬件报警5.3 温度曲线设置的建议我调试过好几台机器总结出一个经验不要一开始就追求极限静音。第一次跑曲线时把不同温度点的PWM值都调得偏保守一些先确认散热余量再用一周时间逐步下探。比如60度时先给90约35%噪音能接受就不要降到70。每次调整幅度控制在20%以内否则容易因温差导致风扇频繁变速。另外记住一个常识风扇调速不可能同时满足“极低噪音”和“低温待机”。你需要做的是找到自己机器在可接受噪音下的最大温度点。我自己的标准是CPU满载不超过85度待机不超过55度用这个前提反推曲线而不是先把转速定死再去看温度。最后说一个我自己的用法。我目前的主力PVE节点是超微板子加IPMI方案备用机是普通B360主板加sysfs脚本。两台机器都在脚本里保留了一条“温度超过80度无条件全速”的硬规则区别只是写入方式不同。调试期间我踩过最深的坑是只盯着CPU温度忽略了风扇转速曲线在高负载后没有及时降回来导致噪音一阵一阵的。后来加了滞回逻辑让PWM只有在温度明显回落后才下调体验立刻正常了。希望这篇对正在折腾PVE风扇的你有帮助。
返回列表