Vytvořeno: 8.6.2020
Poznámka k aktuálnosti: Toto je dobový článek. Postup vychází z konkrétního nasazení na Espressobinu s Nextcloudem a nemusí odpovídat dnešnímu stavu systemd, NextcloudPi ani nástrojů kolem storage.
Důležité: Tento článek se týká klasického rotačního HDD. Pro SSD a NVMe se podobné uspávání přeshdparmběžně nepoužívá.
hdparm umožňuje nastavit standby režim rotačního disku. V mém případě šlo o HDD připojený k Espressobinu, kde jsem chtěl snížit hlučnost a zbytečné opotřebení mechaniky. Samotné nastavení ale komplikovalo několik souběžných problémů: Advanced Power Management, procesy probouzející disk a nepřesnosti při sledování /proc/diskstats.
Uspání po 30 minutách idle času odpovídalo hodnotě -S 241:
hdparm -S 241 /dev/sda
Okamžité uspání disku:
hdparm -y /dev/sda
Pro sledování stavu se hodilo průběžné ověřování:
while : ; do /sbin/hdparm -C /dev/sda; sleep 1; done
Nebo:
watch -n 1 hdparm -C /dev/sda
Později jsem zjistil důležitou věc: dotaz hdparm -C /dev/sda mění statistiky v /proc/diskstats, takže může rušit vlastní logiku pro vyhodnocení nečinnosti disku.
Na některých systémech stačilo použít jen -S. Na Espressobinu se disk neuspával vůbec, takže jsem zkoušel i Advanced Power Management přes parametr -B.
Například:
hdparm -B 127 /dev/sda
Nebo kombinaci:
hdparm -B 50 -S 241 /dev/sda
V praxi se ale uspávání chovalo nevyzpytatelně. Disk se někdy neuspal vůbec a jindy usínal dřív, než jsem čekal. Na této cestě jsem nakonec rezignoval.
Nakonec se mi osvědčilo nečekat, že se disk bude uspávat jen podle interní logiky hdparm, ale pravidelně kontrolovat změny v /proc/diskstats a při nečinnosti ručně spustit hdparm -y.
Původní jednodušší verze skriptu:
#!/bin/bash # Get new state from diskstats devcode=$(findfs UUID=hFAc5i-yMtV-UC83-jF99-UnqA-ck7f-qYlnzo | cut -c 6-8) NEWstate=$(cat /proc/diskstats | grep $devcode) echo $NEWstate > /run/diskNEWstate.txt # compare md5 sums md5new=$(md5sum /run/diskNEWstate.txt | sed 's/ .*//') md5old=$(md5sum /run/diskOLDstate.txt | sed 's/ .*//') # if no changes, power down if [ "$md5new" = "$md5old" ]; then hdparm -y /dev/disk/by-id/ata-ST4000VN008-2DR166_ZDH8BP5S echo "going to sleep" fi # Write current state to file echo $NEWstate > /run/diskOLDstate.txt
Skript byl spouštěný přes cron každých 30 minut. Když se obsah /proc/diskstats od minulého běhu nezměnil, disk se uspal.
Později jsem zjistil, že i u uspaného disku se mění některé sloupce v /proc/diskstats. Proto jsem skript rozšířil o odstranění sloupců, které nemělo smysl sledovat:
#!/bin/bash # Get new state from diskstats devcode=$(findfs UUID=hFAc5i-yMtV-UC83-jF99-UnqA-ck7f-qYlnzo | cut -c 6-8) NEWstate=$(cat /proc/diskstats | grep $devcode) del_column () { NEWstate=$(echo $NEWstate | sed -r 's/(\s+)?\S+//'$1) } del_column 14 del_column 13 del_column 7 del_column 6 del_column 4 echo $NEWstate > /run/diskNEWstate.txt # compare md5 sums md5new=$(md5sum /run/diskNEWstate.txt | sed 's/ .*//') md5old=$(md5sum /run/diskOLDstate.txt | sed 's/ .*//') # if no changes, power down if [ "$md5new" = "$md5old" ]; then hdparm -y /dev/disk/by-id/ata-ST4000VN008-2DR166_ZDH8BP5S echo "going to sleep" else #if changes date >> /etc/scripts/sleep.log fi # Write current state to file echo $NEWstate > /run/diskOLDstate.txt
Pokud se použije čistě hdparm, je dobré pamatovat na to, že nastavení po restartu mizí. U systemd systému jsem to tehdy řešil přes vlastní službu:
# /usr/lib/systemd/system/sda-spindown.service [Unit] Description=Set HDD spindown [Service] Type=oneshot ExecStart=/sbin/hdparm -B 241 /dev/sdb RemainAfterExit=yes [Install] WantedBy=multi-user.target
Aktivace služby:
systemctl daemon-reload
systemctl enable sda-spindown.service
systemctl start sda-spindown.service
Nejvíc času zabralo hledání procesů, které disk probouzely. V mém případě šlo hlavně o údržbu Nextcloudu a monitoring stavu disku v NextcloudPi.
První krok bylo omezit frekvenci Nextcloud cronu. Místo každých 15 minut jsem ho nechal běžet jen jednou denně:
crontab -e -u www-data
12 10 * * * php -f /var/www/nextcloud/cron.php
Druhý problém byl v NextcloudPi: zapnutá volba automatického monitoringu zdraví HDD probouzela disk prakticky pořád. Tuto volbu jsem vypnul.