Proč se liší df a du: Hledání skrytých gigabajtů na Linuxu
Příkaz df -h ukazuje 95 % obsazenosti disku, zatímco du -sh /* sečte jen 20 %. Zbývajících 75 % je pro du neviditelných, ale zabírá bloky na disku. Důvodem jsou otevřené deskriptory souborů procesů na odstraněné soubory. df čte superblok souborového systému přímo, du prochází adresářovou strukturu a ignoruje soubory bez záznamů v ní.
Inode ukládá metadata souboru včetně seznamu datových bloků. rm odstraní pouze záznam v adresáři (hard link), počet odkazů inode klesne, ale pokud proces drží deskriptor, bloky zůstanou alokované.
Schéma:
Před rm:
adresář inode bloky
/var/log/ --> app.log --> [blok1][blok2]
^
deskriptor nginx (pid 1234, fd 7)
Po rm:
adresář inode bloky
/var/log/ --> (odstraněno) --> [blok1][blok2]
^
deskriptor nginx
du nevidí soubor v /var/log/, df zaznamenává obsazené bloky.
Klasické případy problému
Rotace logů: logrotate provede rm starého souboru, ale nginx nebo java drží deskriptor od spuštění. Proces zapisuje do odstraněného souboru, df registruje růst obsazenosti, du ne.
Další scénáře:
- Dlouho běžící démoni s otevřenými logy.
- Chyby v čisticích skriptech, kde rm předchází zavření deskriptoru.
- Kontejnery Docker, kde procesy uvnitř drží soubory hostitele.
Problém se hromadí: gigabajty mizí nepozorovaně, dokud se disk nenaplní.
Hledání procesů s odstraněnými soubory
Použijte lsof +L1 pro soubory s NLINK < 1 (odstraněny ze souborového systému, ale otevřeny):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
nginx 1234 www 7w REG 8,1 2147483648 0 12345 /var/log/app.log (deleted)
java 5678 app 3w REG 8,1 536870912 0 67890 /var/log/service.log (deleted)
Klíčová pole:
- COMMAND/PID: proces a ID.
- FD: deskriptor (7w — zápis, číslo 7).
- SIZE/OFF: velikost — zdroj ztracených GB.
- NLINK=0: potvrzení odstranění.
- NAME (deleted): cesta před rm.
Filtr podle velikosti: lsof +L1 | awk '$7 > 104857600 {print}' (soubory >100 MB).
Uvolnění místa bez restartu
Pro proces PID 1234, FD 7:
$ > /proc/1234/fd/7
/proc — procfs v paměti. Příkaz vynuluje soubor přes deskriptor, jádro okamžitě uvolní bloky. df se aktualizuje, proces pokračuje v zápisu do fd 7.
Zkontrolujte: lsof +L1 | grep 1234 — SIZE/OFF=0 nebo prázdné.
Automatizace skriptem:
#!/bin/bash
lsof +L1 | awk '$7 > 104857600 && $9 ~ /deleted/ {print $2, $8}' | while read pid fd; do
echo "Nulujeme $pid/$fd"
> /proc/$pid/fd/$fd
echo "Uvolněno"
done
Prevence problému v logrotate
Vyhýbejte se rm v rotaci. V /etc/logrotate.d/app:
/var/log/app.log {
daily
rotate 7
compress
copytruncate
}
copytruncate zkopíruje log, pak vynuluje originál (> mechanismus). Deskriptor se nemění.
Nevýhoda: mikrozpoždění kopírování — možná ztráta řádků.
Alternativa bez ztrát:
- logrotate: mv starý → nový soubor.
- kill -HUP <pid> (SIGHUP pro znovuotevření logu).
nginx: nginx -s reopen. systemd: systemctl reload nginx.
Monitorování a upozornění
Skript pro kontrolu:
lsof +L1 -F s | awk '/^s/ && substr($0,2)+0 > 104857600 {count++} END {print count+0}'
Vypíše počet odstraněných souborů >100 MB.
Integrace Prometheus:
node_filefd_allocated— růst otevřených fd.- Porovnání df/disk_used vs du sum.
Cron každých 5 min: upozornění při rozdílu >10 %.
Co je důležité
- df ukazuje alokované bloky superbloku, du — soubory viditelné v adresáři.
lsof +L1najde procesy s (deleted) soubory podle NLINK=0.- Uvolnit:
> /proc/PID/fd/FD— vynulování bez restartu. - logrotate copytruncate předchází problému bez HUP.
- Monitorování: skripty na lsof nebo metriky node_exporter.
— Editorial Team
Zatím žádné komentáře.