Warum df und du unterschiedliche Werte anzeigen: Versteckte Gigabytes auf Linux finden
Der Befehl df -h zeigt 95 % Plattenauslastung an, während du -sh /* nur 20 % summiert. Die fehlenden 75 % sind für du unsichtbar, belegen aber Plattenblöcke. Der Grund sind offene Dateideskriptoren von Prozessen, die auf gelöschte Dateien verweisen. df liest den Dateisystem-Superblock direkt, du durchläuft die Verzeichnisstruktur und ignoriert Dateien ohne Einträge darin.
Ein Inode speichert Dateimetadaten, einschließlich der Liste der Datenblöcke. rm entfernt nur den Verzeichniseintrag (Hardlink), die Inode-Linkanzahl sinkt, aber wenn ein Prozess einen Deskriptor hält, bleiben die Blöcke belegt.
Diagramm:
Vor rm:
Verzeichnis Inode Blöcke
/var/log/ --> app.log --> [Block1][Block2]
^
nginx-Deskriptor (pid 1234, fd 7)
Nach rm:
Verzeichnis Inode Blöcke
/var/log/ --> (gelöscht) --> [Block1][Block2]
^
nginx-Deskriptor
du sieht die Datei nicht in /var/log/, df erfasst die belegten Blöcke.
Klassische Fälle des Problems
Log-Rotation: logrotate führt rm auf einer alten Datei aus, aber nginx oder Java hält einen Deskriptor seit dem Start. Der Prozess schreibt in die gelöschte Datei, df registriert erhöhte Nutzung, du nicht.
Weitere Szenarien:
- Langlaufende Daemons mit offenen Logs.
- Fehler in Bereinigungsskripten, bei denen rm vor dem Schließen des Deskriptors erfolgt.
- Docker-Container, in denen interne Prozesse Host-Dateien halten.
Das Problem summiert sich: Gigabytes verschwinden unbemerkt, bis die Platte voll ist.
Prozesse mit gelöschten Dateien finden
Verwenden Sie lsof +L1 für Dateien mit NLINK < 1 (aus Dateisystem gelöscht, aber offen):
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)
Wichtige Felder:
- COMMAND/PID: Prozess und ID.
- FD: Deskriptor (7w — Schreiben, Nummer 7).
- SIZE/OFF: Größe — Quelle der verlorenen GB.
- NLINK=0: Bestätigung der Löschung.
- NAME (deleted): Pfad vor rm.
Größenfilter: lsof +L1 | awk '$7 > 104857600 {print}' (Dateien >100 MB).
Speicherplatz freigeben ohne Neustart
Für Prozess PID 1234, FD 7:
$ > /proc/1234/fd/7
/proc ist procfs im Speicher. Der Befehl setzt die Datei über den Deskriptor auf null, der Kernel gibt Blöcke sofort frei. df aktualisiert, der Prozess schreibt weiter an fd 7.
Prüfen: lsof +L1 | grep 1234 — SIZE/OFF=0 oder leer.
Skript-Automatisierung:
#!/bin/bash
lsof +L1 | awk '$7 > 104857600 && $9 ~ /deleted/ {print $2, $8}' | while read pid fd; do
echo "Nullsetzung $pid/$fd"
> /proc/$pid/fd/$fd
echo "Frei"
done
Problem in logrotate verhindern
Vermeiden Sie rm bei der Rotation. In /etc/logrotate.d/app:
/var/log/app.log {
daily
rotate 7
compress
copytruncate
}
copytruncate kopiert das Log, dann kürzt es das Original (>-Mechanismus). Der Deskriptor ändert sich nicht.
Nachteil: Mikroverzögerung beim Kopieren — möglicher Verlust von Zeilen.
Alternative für null Verlust:
- logrotate: mv alt → neue Datei.
- kill -HUP <pid> (SIGHUP für Log-Neueröffnung).
nginx: nginx -s reopen. systemd: systemctl reload nginx.
Überwachung und Alarme
Prüfskript:
lsof +L1 -F s | awk '/^s/ && substr($0,2)+0 > 104857600 {count++} END {print count+0}'
Gibt Anzahl gelöschter Dateien >100 MB aus.
Prometheus-Integration:
node_filefd_allocated— Wachstum offener fd.- Vergleichen Sie df/disk_used vs du-Summe.
Cron alle 5 Min: Alarm, wenn Abweichung >10 %.
Wichtige Erkenntnisse
- df zeigt belegte Blöcke aus dem Superblock, du zeigt in Verzeichnissen sichtbare Dateien.
lsof +L1findet Prozesse mit (gelöschten) Dateien durch NLINK=0.- Speicherplatz freigeben:
> /proc/PID/fd/FD— Nullsetzung ohne Neustart. - logrotate copytruncate verhindert das Problem ohne HUP.
- Überwachung: Skripts mit lsof oder node_exporter-Metriken.
— Editorial Team
Noch keine Kommentare.