HOOOS

PVE 下 ZFS 机械硬盘休眠全攻略:榨干最后一瓦电的实操指南

0 5 极客老杨 Proxmox VEZFS硬盘休眠
Apple

在家用 NAS 和 Homelab 圈子里,“全天候运行”的电费是一笔无法忽略的开支。尤其是当你在 Proxmox VE (PVE) 中组建了 ZFS 存储阵列后,会发现机械硬盘(HDD)几乎永远在咔哒咔哒地读写,根本无法进入休眠状态。

ZFS 的天生特性(如频繁的事务组提交、元数据更新)以及 PVE 系统自身的监控机制,都是硬盘休眠的“杀手”。

要让 PVE 下的 ZFS 机械硬盘成功休眠,并实现最大化节能,需要从系统服务、ZFS 属性、休眠工具三个维度进行深度手术。以下是完整的实操方案。


为什么你的 ZFS 硬盘永远无法休眠?

在动手之前,必须先揪出不让硬盘睡觉的“罪魁祸首”:

  1. ZFS TXG(Transaction Group)同步:ZFS 默认每隔 5 秒(zfs_txg_timeout)就会将内存中的脏数据刷入硬盘。即使没有任何主动读写,一些后台微小的元数据变动也会触发写入。
  2. atime(访问时间更新):只要你读取了硬盘上的某个文件,系统就会往硬盘写入一个新的“访问时间”。这导致“读”操作变成了“写”操作,直接打断休眠。
  3. PVE 的 pvestatd 服务:PVE 后台有一个守护进程,默认每 10 秒获取一次所有存储(Storage)的状态。这种主动查询会像针扎一样,每 10 秒把快要睡着的硬盘唤醒一次。
  4. 系统日志与监控:如果你的 PVE 系统(包括 /var/log)或者虚拟机的虚拟磁盘(特别是 Swap 分区)装在机械硬盘上,休眠是根本不可能实现的。

第一阶段:前置准备与系统调优

要让硬盘休眠,必须先满足**“无物理读写打扰”**的前提。

1. 确保系统盘与数据盘物理分离

这是最基本的前提。 PVE 系统本身、虚拟机的系统盘(尤其是带有高频写入的容器,如 Home Assistant、Docker 等)必须安装在 SSD 上。机械硬盘盘阵只用来做纯粹的冷数据存储(如电影、备份、大文件归档)。

2. 关闭 ZFS 的 atime 属性

关闭访问时间更新,让纯粹的“读”操作不触发写入。
在 PVE 终端执行:

# 将 your-pool-name 替换为你的 ZFS 池名称
zfs set atime=off your-pool-name

这个设置对性能也有微弱提升,且对普通数据安全无任何影响。

3. 驯服 PVE 的 pvestatd 频繁扫描

PVE 的后台扫描是休眠的最大障碍。如果你的 ZFS 池只是用来挂载给特定虚拟机(如 OpenWrt 或 TrueNAS),或者通过 Samba 共享,千万不要在 PVE 的 Datacenter -> Storage(数据中心 -> 存储)里添加这个 ZFS 存储。

  • 原理:一旦在 PVE 存储里启用了该 ZFS,PVE 就会定时对其进行 zfs list 等查询。
  • 正确做法:在 PVE 的 Web 界面中删除该 ZFS 存储条目(这不会删除你的数据和池,只是不让 PVE GUI 监控它)。数据的挂载和共享,直接在 PVE 宿主机底层通过命令行、Samba、NFS 或者将硬盘/控制卡直通给虚拟机来完成。

第二阶段:部署专属休眠工具 hd-idle

在 Linux 下,传统的 hdparm 在面对 ZFS 或者是通过 HBA 卡、USB 外置连接的 SAS/SATA 硬盘时,经常失效或无法精确控制。

目前最稳定、效果最好的解决方案是使用 hd-idle。它通过监听 /proc/diskstats 来判断硬盘是否真的空闲,并在超时后强制发送 SCSI 停转指令。

1. 安装 hd-idle

在 PVE 8 (基于 Debian Bookworm) 中,可以直接通过 apt 安装官方源中的版本,或者编译安装最新版。这里推荐直接使用 apt 安装:

apt update
apt install hd-idle -y

2. 获取需要休眠的硬盘 ID

不要使用 /dev/sda 这种随重启会变化的盘符。我们必须使用唯一的、基于硬件的 ID。
执行以下命令,找到你 ZFS 阵列中机械硬盘的 ID:

ls -la /dev/disk/by-id/

通常会看到类似 ata-WDC_WD40EJRX-XXXXXXscsi-SATA_WDC_WD40EJRX-XXXXXX 的一长串字符,记下它们。

3. 配置 hd-idle

编辑配置文件:

nano /etc/default/hd-idle

将文件内容修改为如下模板:

# 启用 hd-idle
START_HD_IDLE=true

# 默认参数:-i 0 表示默认不对所有硬盘进行休眠(避免误伤 SSD 系统盘)
HD_IDLE_OPTS="-i 0"

# 针对具体的机械硬盘设置休眠参数
# -a 后面接硬盘在 /dev/disk/by-id/ 下的软链接路径
# -i 1800 表示空闲 1800 秒(30分钟)后进入休眠
HD_IDLE_OPTS="$HD_IDLE_OPTS -a /dev/disk/by-id/ata-WDC_WD40EJRX-XXXXXX -i 1800"
HD_IDLE_OPTS="$HD_IDLE_OPTS -a /dev/disk/by-id/ata-WDC_WD40EJRX-YYYYYY -i 1800"

如果有多个硬盘,按照上面的格式多写几行 HD_IDLE_OPTS="$HD_IDLE_OPTS -a ... -i 1800" 即可。

4. 启动并开机自启

systemctl enable hd-idle
systemctl restart hd-idle

第三阶段:高级调优(最大化节能与防意外唤醒)

完成了上述两步,硬盘基本可以实现休眠,但在实际使用中,你可能会遇到“刚睡着又被莫名唤醒”的尴尬情况。以下是进阶调优手段:

1. 调整 ZFS 的脏数据写入间隔(慎用)

ZFS 默认的 zfs_txg_timeout 是 5 秒。如果在非生产环境的纯家用冷存储场景下,你可以通过延长这个时间,减少硬盘零星写入的频率,给 hd-idle 创造更宽裕的休眠判定时间。

创建或编辑 ZFS 配置文件:

nano /etc/modprobe.d/zfs.conf

加入以下内容(将同步间隔延长到 30 秒):

options zfs zfs_txg_timeout=30

保存后,更新 initramfs 并重启 PVE:

update-initramfs -u -k all

注:延长此时间会增加系统在意外断电时丢失最近 30 秒内写入数据的风险。家用有 UPS 的情况下可以放心调整。

2. 排查“究竟是谁唤醒了我的硬盘”

如果发现硬盘无法休眠,或者休眠后迅速被唤醒,可以使用 iotop 工具进行实时排查。

安装 iotop

apt install iotop -y

运行监控命令,只显示有实际磁盘写入的进程:

iotop -o -P -d 5

观察在硬盘理应休眠的时间段内,有哪些进程(如 pve-ha-lrmsmartdsyslogd 等)在频繁往磁盘写入数据。针对性地将这些服务的缓存或日志路径重定向到 SSD 上。


避坑指南与寿命考量

  1. 不要设置过短的休眠时间
    家用场景下,建议将休眠超时时间(-i)设置为 1800 秒(30 分钟)或 3600 秒(1 小时)。千万不要设置成 5 分钟或 10 分钟。
    机械硬盘最怕频繁的起停(Start/Stop)。频繁的电机起停对轴承和磁头的损伤,远大于持续旋转的磨损。如果一天内起停超过 10 次,不仅无法有效节能,反而会大幅缩短硬盘寿命(注意关注 SMART 信息中的 Load_Cycle_CountStart_Stop_Count)。

  2. 多盘阵列的唤醒联动
    在 ZFS 阵列(如 RAIDZ1/RAIDZ2)中,读取任何一个文件都会导致阵列中的所有硬盘同时被唤醒。这是 ZFS 的工作原理决定的。因此,如果你频繁需要读取少量小文件,建议在 SSD 上做一个热数据缓存区,避免频繁惊醒整个机械阵列。

通过以上这套方案,你的 PVE 机械硬盘阵列在无任务时,将能够维持在极其安静且省电的“Standby”状态。以 4 盘位 WD 慢速红盘为例,休眠后整机功耗可直接下降 15W - 20W 左右,一年下来省下的电费相当可观,同时也极大地改善了家中的噪音环境。

点评评价

captcha
健康