解决群晖DSM7.2硬盘频繁唤醒问题
更新日期:
前言
群晖的nas系统一直以用户界面易用著称,但是有个问题一直困扰便是群晖的硬盘休眠唤醒问题,个人认为对于机械硬盘来讲应要么禁用唤醒功能,要么应保持长时间休眠状态,频繁的休眠唤醒启动对硬盘故障率可能有一定影响。本文考虑在家用条件下应尽可能让硬盘保持休眠以获得最低的功耗和耗电量。我的群晖型号是DS918+
,已经是几年前的型号了,平时只用来做资料储存,仅安装了Synology Photos
套件作为全家家庭相册和HyperBackup
套件作为备份实现资料的321多重备份储存。并无安装docker,即便在仅仅安装两个套件的情况下出现频繁唤醒问题,足以看出官方系统对于硬盘的休眠是完全不重视的状态。下面只能自行hack解决。
大前提
个人的nas安装了两个nvme
的固态硬盘创建存储区专门存储应用数据、安装套件位置;想要实现机械硬盘休眠的一个大前提便是你需要将docker应用数据、套件等安装在一个固态储存介质的储存区上,这样做有增加应用套件数据库文件等随机读写性能和实现机械硬盘休眠两个好处;首先应实现机械硬盘可以休眠的大前提,我们再来讨论减少唤醒频率以实现长时间的连续休眠。本人利用007revad/Synology_HDD_db实现nvme
硬盘创建存储区。
问题根源
群晖频繁唤醒问题简单来讲根源在于其md0
阵列的结构,群晖默认在每个硬盘上划分出一块分区组raid1
即/dev/md0
挂载为根分区,这一设计当然有其优点,即任一单硬盘即可保存配置完整的启动系统,但是缺点是对于任意根分区的读写都会即刻同步到所有硬盘造成读写,这样的读写多数时间是在写一些例如日志文件、临时的数据库文件等等,绝大多数读写都是不必要的读写,提高了功耗;这些临时文件重要性不能说完全没有,只能说微乎其微,甚至根分区上的系统文件本身的重要性都是微乎其微,绝大多数家用环境人们只会在意数据存储区的数据,至于系统配置文件可以通通过定期备份解决,日志、临时文件我估计许多人几年都不会看一下,我只在排查休眠问题的时候才看下/var/log
里面的日志,把系统提到这样高的重要等级以至于每份硬盘都存一份系统这样的设计我个人认为是意义不明的设计。完全可以找两个ssd介质的硬盘组raid1
储存系统,可靠性足矣;或者可以给用户以选项选择系统是否需要在每个硬盘上存一份或者可选在哪个硬盘上存。
主流做法
遇到这样的问题,网络上的主流做法无非是定期将机械硬盘从/dev/md0
剔除,然后再指定时间定期同步,这么做系统可能会提示系统分区异常(未测试),不太优雅;那么本文此次详细找出到底是什么读写在阻止长时间休眠。
排查休眠日志
首先应在群晖的技术支持中心套件里面启用硬盘休眠日志,关闭所有网页和网络文件共享静置一段时间,通常是一天左右,然后ssh登录nas,正常会在/var/log
目录下生成hibernationFull.log
,此文件相当长,我们需要先过滤无关读写。
无关读写1
对于tmpfs
和proc
的读写不会唤醒磁盘,可以剔除。
无关读写2
对于nvme
磁盘的读写一般不会唤醒磁盘,可以剔除。
无关读写3
对于dm-x
设备的读写,区分讨论,我的nas有一个两个nvme
组raid1
的存储区,它在群晖里面的结构是device mapper(dm-x
)的格式,首先找到存储区编号,我的是volume3
,使用mount
命令输出所有挂载,找到volume3
对应的是什么设备,我的是cachedev_0
,使用lvdisplay
找到对应的dm-x
(最后冒号后面的数字),我的是dm-2
。因此,日志里面所有对于dm-2
的读写一般不会唤醒硬盘,可以剔除。
无关读写4
对于硬盘唤醒后硬盘唤醒本身触发的读写应忽略,一个经典的例子是硬盘唤醒后,scemd
进程会实时调整指示灯等并将相关事件写入日志,这样的读写是硬盘唤醒本身导致的,并不是硬盘唤醒的原因,应该忽略这些日志。
无关读写5
硬盘唤醒之后相关一系列的读写可以不必多关注,我们重点一般只关注造成硬盘唤醒的首次读写分析其来源即可。
日志过滤总结
用以下脚本过滤以上这些无关日志到新日志文件(把dm-2
替换成你对应纯SSD的存储区dm-x
):
1 | sudo awk '!/tmpfs|proc|loop|dm-2|sysfs|nvme/' /var/log/hibernationFull.log > /tmp/hibernationFullslim.log && vim /tmp/hibernationFullslim.log |
日志分析
剩余日志大致可以分为两类,一类是对于/dev/md0
的读写,另一类是除了以上纯SSD设备的dm-x
设备(机械硬盘存储区)(挂载设备/dev/mapper/cachedev_N
)的读写,日志里面写明了文件系统(并非设备本身例如sdx
设备的那条读写记录)读写的block
号,我个人用的是ext4
文件系统,可以用以下脚本找到对应读写的文件(有可能当时读写的文件已经删除显示找不到)。
1 |
|
脚本使用示例:
1 | #run as root |
唤醒原因
以下是我找到的一些唤醒原因及解决方法,这些修正脚本可直接写进/etc/rc.local
/var/log
目录内的日志读写和滚动
绝大多数日志对我用处不大,直接挂载为tmpfs
,只要tmpfs
足够大,压根不需要频繁滚动日志唤醒硬盘,也可计划任务定期清理日志即可。
1 | # rc.local |
SMB服务读写临时文件
这部分有待验证,Samba
服务会读写/var/lib/samba
,无论启动Samba
文件服务与否,都会有nmbd
服务唤醒硬盘,我这边直接关闭nmbd服务(我已经在界面禁用了samba服务)。
1 | mount -t tmpfs -o nosuid,noexec,nodev,mode=0755,size=100M transientlog /var/cache/samba |
FTP服务定期读数据文件
一个是读取ftpd
二进制本身,另一个是ftpd
程序会读取/usr/share/icu/64.2/icudt64l.dat
,尝试用vmtouch
直接加载进内存。
1 | vmtouch -dl /bin/ftpd |
群晖内置及安装应用的计划任务
使用这个脚本:007revad/synology_hibernation_fixer解决,建议拉长间隔或删除一些没用的计划任务,我这边内置了大概34个计划任务。分布在这三个目录:
1 | /usr/syno/share/synocron.d/ |
而且群晖的内置服务使用crontab
的格式,触发时间使用了随机数,不在固定时间触发,无疑加大了唤醒排查难度,意义不明的设计。
群晖的意义不明的唤醒机制
休眠时仅SSD有读写活动scemd
也会一并唤醒所有机械硬盘
同使用这个脚本:007revad/synology_hibernation_fixer解决,它会patch scemd
和synocached
。
IPv6/IPv4地址变化
IPv6/IPv4地址变化会触发一些根分区hook脚本执行,可以用vmtouch
把这些hook加载进内存,我这边是ipv6动态,ipv4静态,未测试ipv4的变化情况:
1 | vmtouch -dl /usr/syno/plugin/net/* |
snmpd定期执行
无论在界面启用与否,snmpd都定期执行,看了service文件界面的snmpd启用与否只会影响是否监听外部连接。
一种办法是直接停止服务(会导致界面没办法看到CPU/MEM使用)
1 | systemctl stop snmpd |
另一种办法是尝试加载二进制进内存:
1 | vmtouch -dl /bin/snmpd |
AME定期读取授权文件
这个授权文件许久都不会变化,加载进内存
1 | vmtouch -dl /usr/syno/etc/license/* |
可能频繁的磁盘信息收集与测试
磁盘数据也可以挂载tmpfs
1 | mount -t tmpfs -o nosuid,noexec,nodev,mode=0755,size=100M transientlog /var/lib/diskutil |
Photos设备不定期上传照片(正常)
貌似即便没有照片上传也会不断读api.so,可以加载进内存减少唤醒
1 | vmtouch -dl /usr/lib/libwebapi-DSM5.so |
界面设置的计划任务执行(正常)
无论你的计划任务本身涉及不涉及磁盘读写,它执行后都会记录执行结果到/usr/syno/etc/sched_status.sqlite
。
界面设置的配置文件自动备份功能(正常)
如果你设置了定期备份系统配置的话。
其他应用及docker
如果你还安装了其他套件或docker,请使用以上方法自行排查对应的程序。
其他杂项
群晖开机会尝试启动一个叫syno-nic-supported-check.serviced
的服务,这个服务会去执行/usr/syno/bin/syno_check_nic_supported
这个文件,但是这个文件压根不存在,导致服务failed
,进而导致systemctl is-system-running
返回degraded
而不是running
,意义不明的设计。
总结
以上,如有错误欢迎指正。