Vorbereitungen zum Umstieg auf den Webcluster: Performance

Seit einiger Zeit (seit mehr als ein Jahr) wollen wir mit den zentralen Webservern auf eine Clusterlösung umsteigen.
Das sowas auf Papier und Hochglanzfolien sowas ganz fix präsentiert wird, spiegelt aber leider nicht die Realität des Alltags wieder, indem man eben nicht sofort alle Server fertig konfiguriert im Serverraum stehen hat. Und in der man eben auch sehr viel normales „Alltags“- und Projektgeschäft zu tun hat.
Tolle Hochglanzprospekte oder kurze Tutorials erzählen nämlich auch nichts von den notwendigen Vorarbeiten in Bezug auf die Netzarchitektur. Sie erzählen nichts davon, daß bei einem Webcluster die gesamte Logging- und Statistikverwaltung neu organisert werden muss. Man hört zwar Sätze, wie „ja mit Syslog-NG, funktioniert das ganz toll“, aber alle Manuals und Anleitungen hören da auf wo es richtig interessant und wichtig wird.

Auch und gerade das Thema Performance ist so vertreten. Es gibt ettliche, tausende, viel und viel zu viele Artikel im Netz, die erklären, wie man die Performance eines Webservers verbessern kann.
Die meisten der Tipps sind aktuell und richtig. Einige jedoch schon veraltet und mit Vorsicht zu geniessen – wie beispielsweise die Empfehlung, daß man seine Webseiten nur gezippt ausliefern soll. (Das war in Zeiten schwacher Bandbreite richtig; Heutzutage, wo man sehr viele Seiten hat, die während der Ladezeit über Ajax-Requests dynamisch modifiziert werde, wirkt sich solche Maßnahme im Gegenteil als Bremse aus).
Wie auch immer: Was ist zu tun, wenn alle diese Empfehlungen bereits umgesetzt wurden und die Performance dennoch zu wünschen übrig lässt?
Denn dann findet man fast nichts im Web.

Daher hilft es oft nichts, es geht nicht ohne zeitaufwendiges Testen, Experimentieren und nochmaliges Testen.

Die Performance der Webauftritte auf den 5 zentralen Server ist derzeit unbefriedigend.

Was sind die Hintergründe davon?

500 Webauftritte verteilen sich auf diese Server. Die Mehrheit aller Webauftritte wird dynamisch erstellt. Seit es über komplexe CMS oder Redaktionssysteme, sei es durch den Einsatz von CGI (Perl oder PHP)-Skripten oder durch die Nutzung von Server Side Includes. Vgl: Übersicht der verwendeten Generatoren, Editoren oder Systeme.

Aber nicht nur die dynamisch erstelten Inhalte drücken auf die Performance, auch die Auslieferungsart und die Größe von vorhandenen Bilddateien, die nicht fürs Web optimiert wurden.
Und zu aller letzt spielt natürlich auch die Hardware selbst eine Rolle, die inzwischen in die Jahre gekomen ist.

Wie kann man die Situation verbessern?

Die ersten Tests werfen den betreffenden Webadmin jeweils in eine der beiden emotionalen Zuständen:
Himmelhochjauchzend oder zu Tode betrübt.

Vorbemerkung: Für alle folgenden Tests wurde der Browsercache abgeschaltet und kein Proxy verwendet! Das mit diesen beiden Funktionen des Browsers eine Seite viel schneller da sein kann ist selbstverständlich. Aber uns geht es um den echten Zugriff auf die Webseite.
Zudem werden alle Möglichkeiten der Optimierung der konkreten Webauftritte erstmal ausser acht gelassen. Zwar könnte man genau an dieser Stelle auch mit der Seitenoptimierung beginnen und das Ladevolumen durch optmierteres CSS und Bilder-Sprites gravierend verbessern, aber darum soll es erstmal nicht gehen. Wir stehen erstmal in der Rolle des „Providers“. Und als dieser können wir nicht in die einzelnen Webauftritte eingreifen und daher auch weder die CGI- und PHP-Skripten optimieren, noch die Struktur der Webseiten oder den Content ändern.

Das erste Screenshot zeigt den Zeitverlauf beim Laden der RRZE-Homepage über einen der Testserver, wenn dieser so konfiguriert wäre wie bisher:

Apache mit Deflate

Man sieht, daß bis zum vollständigen Laden aller Bestandteile der Startseite 1.38 Sekunden benötigt werden. Insgesamt wurden dazu 38 einzelne Dateien aus dem Web geladen.

Die index.shtml ist mit 4.5kB recht klein gehalten. Was daran liegt, daß sie über mod-deflate im ZIP-Format an den Browser geliefert wird. Die Datei ist dennoch erst nach 1.15 Sekunden ausgeliefert.
Die geringe Dateigröße erscheint zunächst also als Vorteil.
Doch wie man am Ladebalken sieht, können alle anderen Elemente erst gealden werden, nachdem die index.shtml am Browser angekommen, entpackt und interpretiert wurde. Erst danach starteten die Subrequests.

Um dieser Verhalten zu verbessern bestand der erste Schritt darin, die Auslieferung im ZIP-Format wieder abzuschalten. Die folgende Grafik zeigt die Auswirkung deutlich:

Apache ohne Deflate

Zwar dauert das Laden der index.shtml-Datei immer noch 1.18 Sekunden, jedoch erhält der Browser bereits nach etwa 0.4 Sekunden erste interpretierbare Teile der Seite. Diese sind ausreichend, damit der Browser erkennen kann, welche Dateien als nächstes geladen werden können.

Die Gesamtzeit um alle Elemente der Webseite zu erhalten ist nun zwar nicht viel besser geworden; Aber dadurch, daß der Browser bereits nach wenigen Millisekunden anfangen kann, Grundstrukturen der Seite aufzubauen und diese auch anzeigt, erscheint die Seite für den Benutzer subjektiv als schneller da: Denn er sieht bereits Teile, während andere erst noch geladen werden.

Als Fazit hierzu kann man also sagen: Die Komprimierung von HTML-Seiten sollte abgeschaltet werden. Sie sollte jedoch beibehalten werden für andere Dateien. Nämlich solche, die erst interpretiert werden müssen, wenn sie vollständig geladen wurden: Reine XML-Dateien (aber kein XHTML), Plaintext, JavaScript, CSS-Code.

In der Apache-Konfiguration sieht dies wie folgt aus:

  AddOutputFilterByType DEFLATE text/xml text/plain text/css application/javascript

Was kann man noch tun im Apache tun?
Zunächst natürlich alle üblichen Empfehlungen folgen: Vgl: Apache Performance Tuning

Der nächste wäre die Nutzung des Modules mem-cache.
Hier wird der Inhalt von Webseite vom Pache zwischengespeichert und dann ausgeliefert. Er arbeitet dabei so wie ein Proxy. Man kann mit Hilfe von mod_mem_cache im RAM und mit mod_disk_cache auf der Festplatte zwischenspeichern.

In meinen Testfall hab ich mich erstmal für mod_mem_cache entschieden.
Der zweite und folgende Zugriffe auf dieselbe Webseite werden bei Nutzung des Clientprozesses des Apaches aus dem Cache bedient.
Der Screenshot zeigt den Performancegewinn:

Apache mit Mem-Cache

Die gesamte Seite, inklusive aller Elemente, wurde nach 390ms ausgeliefert. Die index.shtml-Datei selbst war nach 136ms komplett beim Browser. Damit sind wir unter der Grenze von 200ms, die man nach neuesten Untersuchungen über Usabilty für Websites anstreben sollte.
Wird dann noch der Browsercache benutzt, wird beim wiederholten Zugriff die Ladezeit zusätzlich noch von 390ms auf unter 200 Millisekunden reduziert.

Diese Ergebnisse sind jedoch kein Grund sich auszuruhen. Denn nicht immer wird eine Seite aus dem Cache geliefert. Und dann dauert sie doch wieder etwa 1.2 Sekunden.
In weiteren Tests werden wir daher prüfen müssen, ob wir an der reinen Erstellung von dynamischen Webseiten noch etwas drehen können um auch dort Performancegewinne zu erzielen.

Die MCache-Konfiguration

Folgede Konfigurationseinstellungen wurden nach einigen weiteren Tests für mem:cache vorgenommen:

CacheEnable mem /
CacheDisable /css
CacheDisable /grafiken
CacheDisable /img
CacheIgnoreNoLastMod  On
MCacheSize                     320000
MCacheMaxObjectCount 5000
MCacheMinObjectSize     100
MCacheRemovalAlgorith  LRU

Zunächst hab ich die bei uns üblichen Standardpfade für Bilder Bilder herausgenommen. Die Bilder sind in der Regel klein genug, als das die Nutzung des Caches nicht viel bringt. Stattdessen würden aber die vielen Bilder den Cache schnell aufblähen und so den Platz für die Seiten wegnehmen, die wirklich gecacht werden sollten.
Ausserdem wurde das CSS-Verzeichnis herausgenommen, da einige Tests zeigten, daß einige Browser Probleme mit der Rückgabe vom cache hatten: In den Fällen wurde dann das CSS nicht richtig interpretiert und die Seite verstümmelt angezeigt.

Weiterhin wurde mit der Eigenschaft CacheIgnoreNoLastMod On bewirkt, dass auch dynamisch erstellte Seiten geacht werden. Diese erhalten ein künstlich gesetzes Last-Modified-Datum.

Eine weitere wichtige Angabe für den Mass Hosting Betrieb ist die Nutzung des Algorithmus LRU.
Diese bewirkt das High-Traffic-Seiten im Cache bleiben und nicht etwa Seiten die nur entsprechend von ihrer Größe her sinnvoll cachebar wären.

In weiteren Tests muss sich aber noch zeigen inwieweit diese Konfigurationseinstellungen noch weiter optimiert werden müssen und wie diese sich im Vergleich zu anderen Apache-Konfigurationen verhalten.