====== Espressobin: uspávání rotačního HDD pomocí hdparm ======
//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řes ''hdparm'' běžně nepoužívá.
[[https://wiki.archlinux.org/index.php/hdparm|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''.
===== Základní nastavení přes hdparm =====
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.
===== Advanced Power Management =====
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 [[https://en.wikipedia.org/wiki/Advanced_Power_Management|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.
===== Vlastní skript nad /proc/diskstats =====
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 [[https://cs.wikipedia.org/wiki/Cron|cron]] každých 30 minut. Když se obsah ''/proc/diskstats'' od minulého běhu nezměnil, disk se uspal.
===== Vylepšená verze skriptu =====
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
===== Automatické nastavení po restartu =====
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
===== Co disk probouzelo =====
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.
{{hardware:jednodeskove-pocitace:espressobin:pasted:nextcloud-hdd-health-monitor.jpg}}
===== Zdroje =====
* [[https://wiki.archlinux.org/index.php/hdparm|hdparm – ArchWiki]]
* [[https://en.wikipedia.org/wiki/Advanced_Power_Management|Advanced Power Management]]
* [[https://cstan.io/?p=8766&lang=en|Short tip: configure hard drive standby with systemd]]
* [[https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats|Linux procfs diskstats]]
* [[https://stackoverflow.com/questions/15361632/delete-a-column-with-awk-or-sed/38145415|Delete a column with awk or sed]]
* [[https://bbs.archlinux.org/viewtopic.php?id=216832|hdparm: HDDs spindown after 10 sec, ignoring hdparm -S setting]]
* [[https://unix.stackexchange.com/questions/410264/hdd-idle-settings-using-hdparm-apm-suspend|HDD idle settings using hdparm (APM, Suspend)]]