Um meinem Mini-Server dazu zu verhelfen, so wenig Strom zu verbrauchen und auch die Festplatten-Lebensdauer so wenig wie möglich zu strapazieren, habe ich eine Möglichkeit gesucht und auch gefunden, wie man die Festplattenzugriffe auf quasi Null reduzieren kann. Folgende Schritte waren hierzu nötig:
1. Die aktuellen Festplattenzugriffe ansehen
Wichtig ist in dem Zusammenhang, das man herausfindet, was denn so alles auf der Festplatte passiert. Das geht, in dem man per echo 1 >/proc/sys/vm/block_dump das Loggen einschaltet und dann per tail -f /var/log/syslog beobachtet, was da so alles passiert. Das sieht dann z.B. so aus
bash(8640): dirtied inode 1134246 (.bash_history) on sda2
pdflush(125): WRITE block 36440088 on sda2
Ist man fertig, sollte man das loggen per echo 0 >/proc/sys/vm/block_dump abschalten, denn wenn viel auf der Platte los ist, kann die Logdatei schnell sehr groß werden.
Bei mir wurde schnell deutlich, dass alle Systemlogger in /var schreiben und Apache und MySQL auch ständig auf /var zugreifen. Die schlimmsten IO-Spamer waren allerdings kjournald und pdflush.
2. System-Zugriffe auf die Festplatte minimieren
Es kamen insgesamt zwei Möglichkeiten in Frage: 1. eine FlashDisk benutzen und 2. eine Ramdisk. Flash hat bei vielen Schreiboperationen ein Problem mit der Lebensdauer, eine RamDisk ist futsch, wenn der Rechner abschmiert.
Ich habe mich für die RamDisk entschieden, da man in definierten Abständen einfach per rsync die Daten auf die Platte schreiben kann. Dafür habe ich das “disk2ram” Start-Script erstellt (siehe unten “Script-Versionen”), was das ganze komplett und sauber für mich erledigt. Dieses Script macht folgendes:
Nachtrag: der Teil im Script zum Neustart aller Prozesse enthielt einen Fehler und ist in der aktuellen Version korrigiert
- je eine dynamische Ramdisk für /tmp (128MB) und /var (256MB) erstellen. Diese verbrauchen nur so viel RAM wie Daten enthalten sind und sind von der Maximalgröße eingeschränkt
- je einen logischen Einhängepunkt für /var und /tmp auf der Festplatte erstellen, um später separat darauf zugreifen zu können
- einen Einhängepunkt für die RAM-Laufwerke erstellen
- Den Inhalt von /var und /tmp per rsync in die RamDisk schieben
- /var und /tmp mit den jeweilige RamDisks überlagern
- Alle laufenden Prozesse mit -SIGHUP neu starten
Es ist im übrigen nicht der komplette Inhalt von /var in der Ramdisk enthalten. Wegen der seltenen Benutzung und der Größe sind /var/cache, /var/lib/apt und /var/lib/dpkg nicht in den Ram verschoben und nur in die RamDisk rein gelinkt.
Man kann auf die einzelnen Daten von /var und /tmp auf der Festplatte und den Ramdisks über folgende Einhängpunkte erreichen:
- /.disk2ram/tmp.state
- /tmp auf der Festplatte
- /.disk2ram/tmp.volatile
- /tmp auf der Ramdisk
- /.disk2ram/var.state
- /var auf der Festplatte
- /.disk2ram/var.volatile
- /var auf der RamDisk
Folgende Befehle beherrscht das Script:
- disk2ram start
- Lädt wie oben beschrieben, alles in RamDisks und überlagert /var und /tmp
- disk2ram sync
- Schreibt alle geänderten Daten in den RamDisks auf die Festplatte zurück
- disk2ram stop
- Syncronisiert alle Daten auf die Festplatte wie bei sync, entfernt die RamDisks und die Überlagerungen von /var und /tmp
Da das ganze sehr Stressfrei ist kann man es einfach in den Systemstart mit aufnehmen, wenn man das Script unter /etc/init.d/disk2ram ablegt und per update-rc.d disk2ram start 36 S . stop 98 0 6 .
registriert. Dann wird es automatisch beim Systemstart geladen und schreibt beim System-Stop alles auf die Patte und wird sauber beendet.
Mit diesem Update-RC wird disk2ram als Systemscript behandelt und direkt nach dem Einbinden aller mounts aus der fstab gestartet. Gestoppt wird es als letztes der normalen Programme. Danach kommen nur noch systeminerne Dienste.
Damit nicht zwischendrin Daten verloren gehen Synchronisiere ich zusätzlich jeweils ein mal alle 24 Stunden per Cron die Daten auf die Festplatte. Dazu einfach die Datei disk2ram unter /etc/cron.d ablegen und mit den Rechten chown root /etc/cron.d/disk2ram und chmod 644 /etc/cron.d/disk2ram versehen.
3. Lesezugriffe abfangen
Jetzt sind noch viele Schreibzugriffe auf die Platte wegen dirtied inodes. Das ist relativ einfach zu bereinigen, da die meisten daher rühren, dass bei einem Lesezugriff auf eine Datei das Datum des letzten Zugriffes vermerkt wird, Und dieses Datum wird auf die Platte geschrieben, auch wenn die Datei eigentlich schon im Cache (nicht Ramdisk!) ist und gar nicht mehr von der Platte gelesen werden musste.
Dazu in der /etc/fstab einfach die Option noatime verwenden werden statt z.B. relatime und dann einfach den Rechner neu starten, damit die Option wirksam wird. Noatime verhindert, dass eben diese Datumsangaben geschrieben werden und verhindert so sehr viel IO-Spam.
Meine fstab sieht z.B. so aus:
/dev/sda1 / ext2 noatime,errors=remount-ro 0 1
/dev/sda2 /filestore ext2 noatime 0 2
Nicht über das ext2 wundern, dazu komme ich jetzt.
4. KJournald zur Ruhe zwingen
Als das alles erledigt war, gab es keine “sinnvollen” Festplattenzugriffe mehr, nur noch die von kjournald und pdflush. Darüber habe ich bisher folgendes herausgefunden:
- pdflush ist nicht böse.
- Wenn etwas auf die Festplatte geschrieben werden soll, wird das nicht sofort ausgeführt. Dafür gibts unter Linux den Cache, den man mit top auch sehen kann. Alle Daten, die geschrieben werden sollen werden erst mal im Ram zwischengelagert. Ist dann mal Zeit oder eine gewisse Zeit abgelaufen kommt pdflush und schreibt eben diese Daten dann wirklich. Standard sind wohl 30 Sekunden, die maximal vergehen bevor die Daten geschrieben werden. Das beschleunigt die ganzen Festplattenaktivitäten enorm und sollte einfach so bleiben wie es ist.
- kjournald ist halb böse
- Das ist ein Dienst der das Journal vom Dateisystem ext3 auf dem Laufenden hält. Das Journal erhöht die Datensicherheit bei Plattenproblemen und kann für ein schnelleres Auffinden von Dateien sorgen. Es ist also eigentlich nützlich und unter Linux ist ext3 DER Standard. Aber er schreibt Standardmäßig alle 5 Sekunden irgendwas auf die Festplatte. Was genau das ist, habe ich noch nicht herausgefunden.
Also hieß es, kjournald zur Ruhe zu bringen. Den Intervall zum Schreiben kann man pro Partition als mount-Option “commit=[CENTISECOND]” einstellen. Da ich aber nicht weiß, was es für Probleme bringt, wenn ich den Wert z.B. auf 24 Stunden stelle, habe ich das erst mal gelassen und einen anderen Weg gewählt, nämlich ein “Downgrade” auf ext2.
Der Unterschied von ext3 zu ext2 ist eigentlich NUR das Journal, der Rest ist gleich. Das ist auch der Grund, warum man Problemlos zwischen beiden hin und her wechseln kann. Folgendes muss man dafür machen:
- in der Datei /etc/fstab “ext3″ in “ext2″ ändern
- In der fstab den Dateisystem-Typ aller Platten, die auf ext2 gewechselt werden sollen, entsprechend anpassen, da sonst beim Neustart nach den Änderungen das System nicht mehr hochfahren will
- Das System im “Recovery-Modus” booten
- Das ist nötig, da die Festplatte die als / verwendet wird, nur im Read-Only Modus angepasst werden kann oder wenn sie gar nicht eingehangen ist.
- “root” im Menü auswählen
- …
- mount
- Nachsehen, welche Festplatte wo eingehangen ist
- umount /
- Alle Festplatten, die auf ext2 wechseln sollen, aushängen
- tune2fs -O ^has_journal /dev/sda1
- Die Hat-ein-Journal Markierung von den gewünschten Festplatten entfernen
- fsck /dev/sda1
- Das Journal entfernen. Das passiert bei einem Check automatisch. Ohne diesen Schritt ändert sich gar nichts
- reboot
- Das System wieder ganz normal starten
Danach kann man wieder in die IO-Log (siehe oben) sehen und die Stille genießen. Bei mir gibt es nur noch Festplattenaktivitäten, wenn jemand per FTP was hoch lädt oder sich per SSH eingeloggt wird und beim Synchronisations-Cron alle 24 Stunden. Apache, MySQL und das System selber schweigen komplett.
Nächste Schritte
ext3 ist schon sicherer als ext2. Ich werde also noch suchen, was dieser 5-Sekunden-Spam zu bedeuten hat und ob man den bedenkenlos auf 24h stellen kann.
Nachtrag: der journal-spam scheint irgendwo am System zu hängen. Ich habe eine ext3-HD als /home verwendet und die wird nicht zugemüllt. Das wirft nur noch mehr Fragen auf 🙁
Außerdem gibt es trotz kompletter Inaktivität der Festplatten Probleme mit dem Power-Management, so dass die Platte nach 1 Sekunde direkt wieder ausgeht oder immer an bleibt. Beides ist nicht wirklich wünschenswert.
Nachtrag: Die Probleme mit dem APM sind leider gravierend, so dass ich es komplett abgeschalten habe.
Noch ein Nachtrag: der cron (/etc/init.d/cron) ist beim Booten manchmal vor diesem Script dran. Auch der versteht das HUP-Signal zum Neustart nicht, weswegen ich ihn in das Script per Hand eingefügt habe. Da ist allerdings Vorsicht geboten, denn nicht auf allen Systemen ist der Name gleich. Ggf. muss das Script dann angepasst bzw. ein Link von /etc/init.d/cron auf den richtigen Namen gesetzt werden.
Was auch noch angesprochen wurde ist, dass es Probeme gibt, wenn unterhalb von /var irgendwelche anderen Dinge eingehangen sind. Ein Mountpoint scheint nur auf eine Stelle zu zeigen und nicht mit ihr verbunden zu sein, was ggf verwirrende Resultate haben kann. Im aktuellen Script sind nur die Unterpunkte /var/run und /var/lock beachtet worden, weil nur die auf meines System existieren. Wenn andere Dinge eingehangen sind, muss das Script angepasst werden.
Nachtrag: mit MySQL und apparmor gibt es in dieser Konfiguration scheinbar gravierende Probleme. Eine Lösung habe ich dafür noch nicht.
Nachtrag: Die Ursache für die MySQL-Probleme sind gefunden und gefixt. Allerdings muss in dieses Script noch eine allgemeingültige Neustart-Funktion eingefügt werden. Ansonsten müssten alle auf /var verweisenden Prozesse im Script mit ihrem Init-Script neu gestartet werden.
Script-Versionen
- version-09/2008 (bis Ubuntu 11.10)
- Diese Version lief unter Ubuntu bis Version 11.10 problemlos und relativ universell einsetzbar. Alle Dienste wurden relativ gut erkannt und entsprechend automatisch gestartet und gestoppt, wenn die RAM-Disk eingesetzt bzw. entfernt wurde. Seit Ubuntu 12.04 funktioniert das nicht mehr, da die Upstart-Methoden gravierend verändert wurden.
- version-06/2012 (ab Ubuntu 12.04)
- Die Version ist seit 4/2012 im Einsatz und läuft unter Ubuntu 12.04 Server. Es mussten allerdings schon einige Anpassungen vorgenommen werden, da die Dienst-Namen nicht immer zu den Start/Stop-Services passen. Gerade Systeminterna, wie der Kernel-Log-Deamon, bringen neuerdings komische Zusatzdienste mit eben komischen Namen mit sich. Da muss man viel rumprobieren. Eine generische Lösung habe ich leider noch nicht, aber es funktioniert soweit… bei mir zumindest. Dieser Blog läuft ja nach wie vor auf einem System mit genau diesem Script (um die SD-Karte, die der HD-Ersatz ist, zu schonen).
- version-09/2012 (ab Ubuntu 12.04)
- Die Version ist seit 9/2012 im Einsatz da es Probleme mit den Diensten ddclient (immer mehr Clients starteten), dhclient3 (zickte einfach mal rum) und php5 (via fcgid… lief auch noch Sekunden nach dem Stop des Apache) gab.