Inodes im Linux: Volle Festplatte, obwohl noch Platz ist?
Kürzlich fiel mein Bundestwitter-Server aus. Bei der Suche nach der Ursache habe ich einige neue Dinge über Linux gelernt, die ich hier dokumentieren möchte.
Die Tweet-Sammel-Cronjobs auf meinem Linux (Ubuntu) Server meldeten sich, dass sie keine Daten mehr schreiben könnten. Ich kenne das Problem schon, wenn zu viele Logs und Backups herumliegen ohne aufgeräumt zu werden.
Diesmal allerdings sagt df -h
, es sei noch ordentlich Platz auf der Platte frei:
Size Used Avail Use% 77G 50G 28G 65%
Nach kurzer Recherche stieß ich darauf, dass nicht nur der Platz auf der Festplatte begrenzt ist, sondern auch die maximale Zahl der Dateien. Wikipedia sagt:
Die Anzahl der möglichen Inodes und somit der möglichen Dateien ist bei manchen Dateisystemen beschränkt; wird die Maximalanzahl erreicht, lassen sich keine weiteren Dateien anlegen.
Also: df -i
.
Inodes IUsed IFree IUse% 1000000 1000000 0 100%
Eine Lösung könnte darin bestehen, die Festplatte neu zu formatieren und die Zahl der möglichen Inodes höher festzulegen. Ob das bei meinem 1und1 VirtualServer so einfach möglich ist, ist fraglich. Zunächst möchte ich aber wissen, wo diese vielen Dateien liegen und woher sie kommen. Bundestwitter legt zwar viele Logfiles für Tweets an, aber diese werden regelmäßig gepackt, heruntergeladen und vom Server gelöscht. Sie erklären die volle Platte vermutlich nicht.
Ich suche also einen Befehl, der mir zeigt, in welchen Verzeichnissen viele Inodes verbraucht werden. Google ist mein Freund:
find /var/www/ -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -n
... listet alle Folder und subfolder mit der Zahl ihrer enthaltenen Inodes auf. Was ggf. sehr lang wird — in meinem Fall knapp 2000 Einträge:
1 /var/www/blog_thomaspuppe_de/assets [... 2000 weitere Einträge ...] 2563 /var/www/bundestwitter/cache/www_bundestwitter_de/connectionStatistics
Das hilft also nur bei überschaubarer Ordnertiefe. Besser ist dieser Befehl, der die Anzahl der Inodes in einem Verzeichnis (oder in jedem Unterverzeichnis) zeigt:
for i in /var/www/*; do echo $i; find $i | wc -l | sort ; done
(ohne "/*" für das einzelne Verzeichnis):
104 /var/www/blog_thomaspuppe_de 76266 /var/www/bundestwitter 2 /var/www/html 1371 /var/www/lab_thomaspuppe_de 32748 /var/www/socialmediapolitik 2 /var/www/thomas_works 3 /var/www/www_meetingtimer_biz 101 /var/www/www_thomaspuppe_de
Es zeigt sich, dass Bundestwitter nicht der Verursacher ist. Aber mit dem genannten Befehl kann ich nun die Ordner des Root-Verzeichnisses auflisten ...
sudo su #(um sich eine Menge "Permission denied" Meldungen zu sparen) for i in /*; do echo $i; find $i | wc -l | sort ; done
... zeigt, dass die allermeisten Inodes in /var
verbraucht werden. (Warum in proc
so viel los ist, wird Gegenstand einer anderen Untersuchung sein.)
16 /home 22271 /proc 29687 /usr 953965 /var
Von hier aus kann ich mich mit dem Befehl for i in /var/*; do echo $i; find $i | wc -l | sort ; done
usw. fortbewegen.
662 /var/log 836952 /var/spool 112120 /var/www
In /var/spool
liegt also sehr viel Zeugs. Dies ist das "Verzeichnis für abzuarbeitende Warteschlangen (Druckaufträge, E-Mail-Versandaufträge …)"
(Wikipedia).
Mit der bekannten Technik taste ich mich weiter voran und stoße auf ein Verzeichnis, in dem fast alle Dateien liegen:
836836 /var/spool/postfix/maildrop
Das sind also felgeschlagene Versuche des Systems, E-Mails zu versenden. Stichproben (cat /var/spool/postfix/maildrop/D7E6A90D4CA9
) ergeben, dass meine Cronjobs versuchen, Mails zu versenden.
Ich habe also meinen Übeltäter. Nun geht es ans Aufräumen.
Die erste Maßnahme, für den Seelenfrieden, ist natürlich
sudo rm -rf /var/spool/postfix/maildrop/* bash: /bin/rm: Argument list too long
Eine schnelle Suche führt mich auf`sysadminslife.com, wo folgender Befehl vorgeschlagen wird:
find -type f -print0 | xargs -0 rm
An der Stelle möchte ich Explainshell erwähnen. Eine Website, die Shell-Befehle aufdröselt und die einzelnen Bestandteile erklärt. http://explainshell.com/explain?cmd=find+-type+f+-print0+%7C+xargs+-0+rm
Ta dah:
$ ls /var/spool/postfix/maildrop | wc -l 14 $ df -i Inodes IUsed IFree IUse% 1000000 143491 856509 15%
Es bleibt die Frage: Wie vermeide ich, dass die Ausführung der Cronjobs Mails erzeugt (die dann in der Spool Queue landen)?
http://www.cyberciti.biz/faq/disable-the-mail-alert-by-crontab-command/:
The crontab command is used to maintain crontab files for individual users. By default the output of a command or a script (if any produced), will be email to your local email account.
Die einfachste Methode, dies zu verhindern, ist die Zeile MAILTO=""
an den beginn der Crontab-Datei (crontab -e
) zu schreiben. Damit werden alle Cron-Mails aus diesr Datei unterdrückt. Alternativ kann man auch pro Zeile den Versand von Mails verhintern durch den Output nach /dev/null: 0 1 5 10 * /path/to/script.sh > /dev/null
.
Kleines Extra: In Zukunft möchte ich eine Warnung erhalten, wenn der Plattenplatz (oder die Inodes) zur Neige gehen. Der Test dafür ist leicht geschrieben (siehe oben), und einen Mechanismus zur Benachrichtigung habe ich schon für andere Zwecke. Und zwar benutze ich den Service und die App von Pushover: Simple Notifications for Android, iOS, and Desktop und Dead Man's Snitch — A dead simple cron job monitoring tool.