拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

KeyarchOS下hd-idle硬盘休眠实战:功耗优化与踩坑记录

KeyarchOS下hd-idle硬盘休眠实战:功耗优化与踩坑记录

运维干了这么多年,我最不愿意交出去的就是“电费”。去年给自己维护的那台浪潮信息 KeyarchOS 存储服务器做了一轮功耗优化,翻了半天负载和硬盘状态,发现真正在烧钱的往往不是 CPU,而是那些一年 365 天都在转的机械硬盘。于是盯上了 hd-idle 这个老牌工具。折腾完 hd-idle-1.05-4,效果最直观:闲置数据盘温度降了 8℃ 左右,整机功耗实打实掉了十几瓦,机房里那台服务器的风扇转速也跟着下来了。这篇就完整写一写,在 KeyarchOS(浪潮信息 KOS)里怎么装、怎么配、怎么验证,以及我顺手踩出来的那些坑。

1. 我先说清楚:硬盘休眠到底在省什么、哪些场景该用

1.1 省下的不只是那几瓦电

机械硬盘的功耗大头在主轴马达和磁头驱动。一块 3.5 英寸机械盘,正常运行时功耗普遍在 6W 到 8W,空闲状态只要盘片还在转,它依然维持在这个量级;真正 spin-down 进入待机后,多数盘能掉到 1W 左右甚至更低。你别小看这五六瓦,一台 8 盘位的存储服务器光硬盘就是 48W 左右的差距,再算上供电转换率和风扇因为发热降速节约的能耗,一个月下来不是小数。

更直接的是散热压力。硬盘休眠之后盘体温度能降好几度,机柜里温度下来了,风扇也不用一直高转速。我调试那天用传感器看了盘体温度,休眠前后的差距非常明显,整机噪音水平也直观改善。所以我不太爱听“省不了几度电”这种说法,服务器长期在线,积少成多,更何况硬盘本来就是消耗品,温度每降一点,都有意义。

1.2 哪些盘值得休眠,哪些盘千万别碰

在动手配置之前,最需要想明白的是“休眠策略到底用在哪一层”。我的判断依据是这样的:

  • 适合休眠的:备份存储池、归档数据、日志归档、冷数据盘、长时间没有随机读写的仓库盘。
  • 完全不适合的:装了操作系统的系统盘、数据库数据盘、虚拟机镜像存储、频繁读写的工作目录。这些盘你让它休眠,等于给应用的每次访问额外增加一次 5~15 秒的硬盘唤醒时间,代价比省下的那点电大得多。

所以 hd-idle 这类工具真正的用武之地,是“多盘 NAS / 冷备机”、“监控存储”和“家庭或小机房的归档服务器”。在这些场景里,大量磁盘可能几小时甚至几天都没有一次真正的 I/O,让它们一直转着纯粹是浪费。

1.3 为什么是 hd-idle,而不是 hdparm -S 或手动打命令

很多人第一反应是“直接用 hdparm -S 不就行了”,这个工具确实能让硬盘在指定时间后自动休眠,原理是利用 ATA 规范里的内置电源管理定时器,把超时参数写进盘体固件。但它有两个局限:一是它依赖硬盘对 ATA 电源管理命令的较好支持,在部分桥接芯片、外接硬盘盒或者某些 SAS 场景下并不生效;二是它只是“设一个定时器”,具体哪块盘什么时候进休眠、为什么没休眠,没有日志可查,出了问题很难排查。

hd-idle 是真正跑在用户态的守护进程,它自己盯着各个块设备的 I/O 状态统计,自己维护一个“空闲计时器”,到点之后主动向硬盘发送 spin-down 命令。好处非常实际:不同盘可以设置不同的空闲时间,系统盘可以直接排除,日志和调试信息一清二楚,还能通过 systemd 做成标准服务。这也是我在 KeyarchOS 上最终选它的原因,配置过程完全在系统层面可控,不会被盘体固件的实现差异牵着走。

2. hd-idle 的空闲判定逻辑:它怎么知道硬盘“没事干”

2.1 轮询统计信息而不是真的去读盘

这里有个容易混淆的点,很多人以为 hd-idle 会周期性地去读硬盘、测试硬盘是不是还“活着”,实际上它根本不碰盘上的数据。它会去读系统里跟块设备 I/O 相关的统计接口,比如 /sys/block/ 下的信息,从而判断自上次访问以来到底有没有新的读写请求。这个设计很重要,因为如果它自己频繁产生 I/O,那硬盘就永远等不到休眠的那一天,那就本末倒置了。

用生活化的例子来说,hd-idle 有点像单位门口查岗的保安:他不进办公室,只在窗口看你工位上有没有人动。只要你一直没动弹,时间一到他就把电闸拉了;你回来之后,自己把电闸推上。

2.2 从“开始计时”到“发出休眠命令”

每块被监控的硬盘都有一个空闲计数器。一旦系统里出现针对这块盘的读或写,计数器立刻归零并重新开始计时。如果计数器走到了你设定的时间值,hd-idle 就会执行一次 spin-down 操作,让盘片停转、磁头归位,进入待机状态。之后如果有新的 I/O 到来,硬盘会被自动唤醒,整个过程对应用层是透明的,应用该读读、该写写,不会报错,只是首次访问会明显比平时慢。

这里面有个细节值得注意:hd-idle 只管“到点休眠”,不负责“定时唤醒”,唤醒是由文件系统或应用触发的。这意味着你要自己评估业务容忍度,如果某块盘休眠后长时间没访问,下一次写入或者备份任务开始时,前面几秒的等待是预期内的,别到时候误判成硬件故障。

2.3 几个命令参数的坑与含义

hd-idle 1.05 的常用参数,我建议这样理解:

  • -i <秒数>:空闲多少秒后休眠。当它跟在某个-a <设备>后面时,表示只针对该设备;单独出现在前面,表示全局默认值。
  • -a <设备>:指定一个块设备路径,比如 /dev/sdb。该参数可以重复出现,每块盘单独配置。
  • -l <文件>:把运行信息写进指定日志文件,排查问题基本靠它。
  • -t:测试模式,校验配置和系统支持情况,不会真正开始监控。
  • -d:打开调试输出,信息量很大,建议排障的时候用。
  • -n:前台运行,不 fork 到后台。配合-d用,可以直接在终端里看到完整流程。

参数组合的顺序是有讲究的,这也是新手最容易踩的坑。-i如果放在最前面,它就是全局默认值;但如果你在后面又写了-a /dev/sdb -i 7200,那么这 7200 秒就是专门给 /dev/sdb 的覆盖值,其他没有被单独列出的盘会沿用前面的全局默认值。我在第 4 节会专门放一份可抄的样例。

3. 在 KeyarchOS 上安装 hd-idle-1.05-4:完整操作流程

3.1 安装前先摸清环境

浪潮信息 KeyarchOS 走的是 RPM 系包管理,对熟悉 RHEL/CentOS 的人来说很亲切。动手之前,我建议先确认几件事:

cat /etc/os-release uname -r lsblk -d -o NAME,SIZE,ROTA,TYPE

ROTA这列非常关键,1 表示机械旋转盘,0 表示 SSD。我在后面的配置里就是要拿它做参考,确认哪些是真正需要休眠的机械盘。执行完这个命令,你至少应该清楚:系统盘在哪、数据盘是哪几块、有没有直通盘之外的 RAID 阵列。

另外,如果你的数据盘已经是某个 RAID 阵列的虚拟盘,比如 /dev/sda 实际是阵列卡虚拟出来的逻辑卷,那么 hd-idle 直接对它操作的可行性会下降,这个我在第 7 节单独说。

3.2 安装的几种路径,按优先级排

在 KeyarchOS 上装 hd-idle 有三个思路,我按推荐顺序写:

第一个思路:用 EPEL 仓库装现成 RPM。KeyarchOS 跟 RHEL 系生态兼容度比较高,默认可能没带 hd-idle,但是通过 EPEL 可以拿到。命令很简单:

sudo dnf install -y epel-release sudo dnf install -y hd-idle

装好之后你会看到一个名为 hd-idle-1.05-4 的包,这正是我标题里写的版本。它自带 systemd 服务文件和默认配置思路,省事很多。

第二个思路:如果内网环境不太方便拉到 EPEL,可以从源码编译。hd-idle 的源码就一个 C 程序,不依赖花里胡哨的库,编译很简单:

sudo dnf install -y gcc make wget <hd-idle 源码包地址> tar -zxf hd-idle-1.05.tgz cd hd-idle-1.05 make sudo install -m 755 hd-idle /usr/sbin/hd-idle

编译之前记得确认依赖,其实核心就是-Wall -O2一把梭,非常轻量。

第三个思路:如果恰好有内部 RPM 仓库或离线软件包,直接用 rpm 装。例如:

sudo rpm -ivh hd-idle-1.05-4.el9.x86_64.rpm

装完顺手执行一下which hd-idle和hd-idle -t,前者确认二进制位置,后者确认工具能识别当前系统环境。-t输出正常的话,基本就可以进入配置阶段了。

3.3 安装完成后的第一个自检命令

我强烈建议安装完成后先跑一次:

/usr/sbin/hd-idle -t

这个命令不是真的进入监控,而是类似于“自检模式”。它会把当前的参数处理逻辑跑一遍并退出,能帮你快速发现参数写没写错、设备路径是否存在。我第一次配置时就是在 systemd 服务里写错了设备名,跑了-t才发现程序只在启动瞬间检查设备,后面全靠日志排查,绕了不少弯路。

4. 配置方案设计:全局默认、单盘策略和一份可抄的配置

4.1 先理解配置的两层结构

hd-idle 1.05 的配置思路分两层:一层是全局默认,另一层是单盘覆盖。你可以在配置文件或者启动参数里先写一个全盘的统一空闲时间,再针对个别盘写专门的时间。比如数据盘里有块盘每天都有同步任务,其他盘一个星期都没人动,那就必须让它俩享受不同待遇。

我实际用的方案是:所有机械盘统一设置一个较长的空闲时间,比如 3600 秒(1 小时),同时用-a逐块排除系统盘和虚拟机数据盘。全局统一的好处是配置简单,但如果你对功耗要求更极致,也可以把备份盘设成 600 秒(10 分钟),把归档盘设成 7200 秒(2 小时),灵活性是 hd-idle 的立身之本。

4.2 参数组合到底怎么理解

先放一段概念上的命令行组合:

/usr/sbin/hd-idle -i 3600 -a /dev/sdb -i 0 -a /dev/sdc -i 600

这段配置的含义是:

  • -i 3600:默认空闲 3600 秒(1 小时)后休眠。
  • -a /dev/sdb -i 0:/dev/sdb 被单独列出,-i 0表示禁用自动休眠。
  • -a /dev/sdc -i 600:/dev/sdc 被单独列出,空闲 600 秒(10 分钟)就休眠。

有没有发现,前面那个全局-i 3600会被后面的单盘-i覆盖。但这个覆盖是“带设备名”的覆盖,不是“所有后续设备”的覆盖。换句话说,每一块你没有用-a单独列出的盘,都会继承最前面那个全局默认值。这就是为什么我建议先把全局写出来,再逐盘覆盖,而不是反过来。

4.3 我实际用的配置样例

这是我当时在 KeyarchOS 上最终落地的方案,可以直接抄:

/usr/sbin/hd-idle -i 7200 -a /dev/sda -i 0 -a /dev/sdb -i 3600 -a /dev/sdc -i 3600 -l /var/log/hd-idle.log
  • /dev/sda 是系统盘,直接-i 0禁止休眠。
  • /dev/sdb 和 /dev/sdc 是数据归档盘,3600 秒没有 I/O 就休眠。
  • 其他盘如果后面再接上,会默认走 7200 秒的全局值。

如果你安装的是 EPEL 版本,它一般会带一个配置文件或者 systemd 环境文件。我建议直接看包内容:

rpm -ql hd-idle

看到服务文件路径之后,可以用 systemd 的 override 模式修改启动参数,保持原始文件不被污染。这在后续升级时会省不少麻烦。如果包自带的是/etc/sysconfig/hd-idle,那就把上面整条命令行写进类似HD_IDLE_OPTS的变量里,服务文件会自动读取它。

5. 用 systemd 把休眠策略跑成常驻服务

5.1 先看安装包自带的服务文件

EPEL 版本的 hd-idle 通常已经配好了一个 systemd 单元文件,一般位于/usr/lib/systemd/system/hd-idle.service。装完以后你可以直接执行:

systemctl cat hd-idle

看看里面ExecStart到底帮我们写了什么。很多时候默认的ExecStart只是/usr/sbin/hd-idle本身,不带任何参数,等于装好之后你不手动改启动方式,它什么都干不了。这也是很多教程含糊其辞的地方。

5.2 没有服务文件时,自己写一个干净的 Unit

如果安装包没带服务文件,或者你想把启动参数全部收进 systemd 体系里,我建议新建/etc/systemd/system/hd-idle.service,内容如下:

[Unit] Description=hd-idle - spin down idle disks After=syslog.target [Service] Type=forking ExecStart=/usr/sbin/hd-idle -i 7200 -a /dev/sda -i 0 -a /dev/sdb -i 3600 -a /dev/sdc -i 3600 -l /var/log/hd-idle.log PIDFile=/run/hd-idle.pid [Install] WantedBy=multi-user.target

这里的关键是Type=forking。hd-idle 启动的时候会自己 fork 到后台并写一个 PID 文件,systemd 需要用这个类型来正确跟踪服务状态。如果你写成Type=simple,systemd 可能会误判服务已经退出,导致状态监控一团糟。

写好之后记得重新加载:

sudo systemctl daemon-reload sudo systemctl enable hd-idle sudo systemctl start hd-idle sudo systemctl status hd-idle

enable负责开机自启,start负责立即启动,两者缺一不可。很多人在这一步只 start 不 enable,结果服务器重启后硬盘又恢复“长转不停”的状态。

5.3 服务跑起来后怎么确认它真的在干活

最直接的办法是看进程和日志:

ps aux | grep hd-idle cat /var/log/hd-idle.log

如果日志文件开始出现类似于“spin down”的记录,说明服务已经进入正常工作状态。如果没有,多半是前面参数没生效,或者是日志路径没权限写。我先写在这里:如果日志迟迟不出现,先检查-l指定的目录是否存在、hd-idle 是否有权限写入,别一上来就怀疑服务没启动。

6. 验证休眠效果:从服务日志到整机功耗实测

6.1 用 hdparm 确认硬盘真实电源状态

日志说休眠了,不代表设备真到待机状态。我习惯再用 hdparm 交叉验证一下:

sudo hdparm -C /dev/sdb

正常的输出会出现类似drive state is: standby的结果。如果显示active/idle,说明硬盘还在转。这个命令很轻量,不会把休眠中的硬盘唤醒,所以你可以放心使用。需要注意的是某些阵列卡或 USB 桥接环境下,hdparm 可能读不到预想的信息,这时候以 hd-idle 自己的日志为准,再辅以盘体温度和功耗数据判断。

6.2 温度和功耗怎么测

温度这个东西最直观。机械盘休眠前后盘体温度差距非常大,你可以装个smartmontools,在硬盘休眠前后分别执行:

sudo smartctl -a /dev/sdb | grep Temperature

如果你不想让 smartctl 干扰休眠策略,一定要给 smartd 的配置加上-n standby之类的参数,让它在硬盘处于待机状态时跳过检测。否则你会遇到一个诡异现象:hd-idle 让盘睡了,smartd 定时器又把它叫醒来查健康状态,硬盘永远睡不踏实,后面第 7 节我详细说。

功耗测量如果手边有条件,建议用机柜 PDU 或者功率计直接看整机输入功率。没有专业设备的话,至少可以通过盘体温度和 CPU/风扇转速的变化来侧面确认。我当时调试完,整机功耗从待机状态起的十几瓦差值是能稳定复现的,24 小时跑下来非常可观。

6.3 长期验证比一次性验证重要

我不建议你配完看一眼日志就宣布“大功告成”。服务器运行一周以后,再回头翻一下 hd-idle 日志,重点看两块盘“休眠-唤醒”的次数分布。如果某块盘一天里被唤醒了上百次,说明这个工作负载并不适合自动休眠;如果日志显示大家沉睡的时间都很长,那这个策略就是成功的。自动休眠这件事,最怕的不是不睡,而是睡了以后频繁被吵醒,那反而会让磁头加载次数暴涨。

7. 踩坑日志:配置 hd-idle 最容易被忽略的 5 个问题

7.1 把系统盘也挂上自动休眠,然后服务全部卡成狗

这是我最想骂人的一次经历。当时为了省事,我把所有机械盘一刀切设了 600 秒休眠,系统盘也在里面。结果某个晚上日志服务突然大面积响应超时,原因很朴素:系统盘休眠后,任何一次写日志或读配置的动作都要先等硬盘从待机状态恢复,那个延迟在吞吐量高的时候被无限放大,进程全部排队卡死。后来我复盘时发现,hdparm 这种工具再怎么牛,也不该对系统盘下手,系统盘的访问模式根本不存在“长时间连续空闲”的可能。所以配置里第一件事就是把系统盘用-i 0锁死,这是任何场景下的底线。

7.2 硬盘频繁唤起的“假休眠”:问题不在 hd-idle,而在 cron

我一度以为 hd-idle 配错了,因为日志显示硬盘每隔半小时就被唤醒一次,但明明业务没有访问它。排查到最后,背锅的是 cron 任务和监控脚本——有些定时任务或 Agent 会定期去某个目录扫一遍文件,或者更新一个文件的 mtime,这个动作看着不起眼,但对于 hd-idle 来说就是一次实打实的 I/O,空闲计时器直接清零。

排查办法也简单:先把 hd-idle 用-d -n跑到前台,观察它检测到活动的时间点,再对应去查那个时间点有什么任务在执行。也可以用fatrace这类工具追踪文件访问来源,按进程归类,基本一击即中。我最终的解决方案是把 cron 任务的扫描路径迁移到专用目录,或者把监控 Agent 的采集频率调低,让它跟休眠策略错开周期。

7.3 在 RAID 阵列卡后面的盘,hd-idle 往往是有劲使不上

如果你用的不是直通 HBA 卡,而是带 RAID 功能的阵列卡,那 hd-idle 能看到的很可能是一个虚拟磁盘,不是物理硬盘本身。它朝这个虚拟盘发 sleep 命令,阵列卡大概率会忽略或处理成另外的局面,因为节能决策在阵列卡自己的控制层上。真遇到这种阵列环境,我的建议是别硬刚 hd-idle,要么改成 HBA 直通模式,要么在阵列卡的管理界面里做它自己的物理盘降速策略。这是我早期差点误判“hd-idle 没用”的根源,换到直通模式后一切正常。

7.4 smartd 的定时自检,亲手把休眠盘喊醒

这个坑值得单独拿出来说,因为它太隐蔽了。smartd 默认会按照你配置的周期去读硬盘的 S.M.A.R.T. 信息,很多发行版默认配置是“每 30 分钟检查一次”。你明明看到 hd-idle 日志里 22:00 休眠了,但 22:30 的 smartd 自检一来,硬盘立刻被唤醒。日积月累,磁头加载次数直线上升,盘体还没省到电,提前损耗倒是来了。

解决办法在 smartd.conf 里给设备加-n standby,15这类参数,意思是“硬盘处于待机或睡眠状态时不检测,如果检测到已在待机状态,就跳过并等待下次”。加完记得重启 smartd。这个细节,几乎每份 hd-idle 教程都不会提,但它直接决定休眠策略能不能长期跑稳。

7.5 调试时的正确姿势:前台模式 + 短空闲时间

调试 hd-idle 配置时,我不建议直接把正式参数塞进服务里然后一遍遍看日志,太慢了。我习惯先用一个很短的空闲时间(比如 60 秒),配合-d -n前台运行:

sudo /usr/sbin/hd-idle -d -n -i 60 -a /dev/sdb -i 120

这样你能在终端直接看到:它是怎么轮询的、什么时候发现空闲超时、发出了什么指令。等确认整套逻辑没问题,再把正式的较长空闲时间写进 systemd 配置。命令行的执行逻辑和 systemd 里的执行逻辑是完全一致的,在终端里验证通过,再放到服务里才算稳妥。

另外还有一个非常容易被忽略的事:日志轮转。hd-idle 的-l日志会一直增长,时间长了之后会占满磁盘。建议给它配一个 logrotate 规则,最简单的方式是在/etc/logrotate.d/hd-idle写:

/var/log/hd-idle.log { weekly rotate 4 compress missingok notifempty copytruncate }

copytruncate这个选项很关键,hd-idle 持有的是文件句柄,普通的 rename 策略可能会让它继续往旧文件里写。

我到现在调试新服务器时,仍然会先把这 5 个坑过一遍,尤其是系统盘白名单和 smartd 唤醒这两条,基本能避免九成以上的“休眠策略无效”问题。硬盘自动休眠这件事,配置本身半小时就能搞定,真正花时间的,是搞清楚后台到底有哪些“看不见的手”在替用户访问硬盘。

返回列表