Serendipity: Performancezentriertes Serversetup
Im September 2012 habe ich dieses Blog auf Serendipity umgestellt. Seitdem habe ich Erfahrungen gesammelt, wie ich meinen Server gut für diese Anwendung einstelle, um eine höchstmögliche Performance herauszuholen.
Motivation
Mir liegt die Performance von Websites sehr am Herzen. Es stört mich, wenn ich warten muss und noch mehr stört es mich, wenn eine Webanwendung wie Serenditpity (S9y), Wordpress usw. zum Beantworten einer Anfrage aufwändige Berechnungen durchführt und diese danach komplett verwirft. Kommt die gleiche Anfrage eine halbe Sekunde später nochmal, muss die Antwort erneut berechnet werden.
In einem 0815-Setup muss ein Webserver für jede Anfrage PHP bemühen, viele Skripte auszuführen, welche wiederum Datenbankabfragen durchführen. Nach diesem Brimborium, kann er die fertiggerenderte Antwort endlich an den anfragenden Webbrowser senden. Wenn es eine etwas durchdachtere Webapplikation ist, benutzt sie selbst Caches, um Berechnungen und Datenbankabfragen zu reduzieren.
Nichtsdestotrotz halte ich alles für unperformant, was über PHP abgewickelt wird. Häufig vorkommende Aufrufe will ich dort nicht permanent durchleiten, es darf schließlich nur wenig Systemressourcen benötigen. Andernfalls reicht es, wenn Fefe einen Link setzt, um die Site zu lüften. Selten vorkommendes wie das Hinzufügen eines Kommentars oder das Editieren eines Blogbeitrags kann ruhig einen Augenblick länger dauern.
Architektur vereinfacht erklärt
In meinem Setup werden HTTP-Anfragen von außen auf Port 80 vom Cache Varnish entgegen genommen. Kennt Varnish die Antwort auf die Anfrage bereits, beantwortet er sie direkt. Wenn nicht, fragt er den Webserver nginx auf dem lokalen Port 8081. Wenn die angefragte Ressource statisch ist, zieht sie Nginx aus dem Dateisystem. Wenn die Ressource auf ein PHP-Skript abzielt, spricht nginx mit php-fpm über das FastCGI-Protokoll auf einem UNIX-Domain-Socket. php-fpm lässt einen neuen oder arbeitslosen Arbeitsprozess die Antwort in Verbindung mit XCache rendern. Dabei auftretende Datenbankabfragen laufen gegen eine SQLite-Datenbank. Varnish merkt sich jede Antwort von nginx für knapp eine Stunde. Ein Cacheanheizer läuft stündlich über die Site und aktualisiert im Varnishcache die wichtigsten Ressourcen.
Das 0815-Setup hat lediglich den Apache-Webserver mit mod_php. Apache führt selbst das PHP bei Bedarf aus und blockiert jeweils einen seiner Arbeitsprozesse dabei. PHP spricht bei Bedarf mit einer MySQL-Datenbank über eine TCP-Socketverbindung.
Varnish
Jede Webapplikation benötigt potenziell eine eigene Varnishkonfiguration. Bei S9y können sogar einzelne Plugins Anpassungen erfordern. Varnish hat eine eigene Konfigurationssprache namens VCL. Sie ist mit der vhost-Konfiguration von Apache vergleichbar, welche auch für jede Site individuell ist.
Bei meinem Blog ist bis auf das S9y-Backend und die Kommentarfunktion alles cachebar. Dem entsprechend habe ich auch meine Konfiguration gestaltet. Die Cacheverfallsdauer ist auf exakt eine Stunde minus zwei Sekunden eingestellt.
Solange die Cacheeinträge nicht veraltet sind, kann ich den Webserver nginx sogar runterfahren. Die Site bleibt verfügbar. Bei anderen Setups kann in Verbindung mit Varnish die Datenbank wegglühen, externe Ressourcen nicht antworten oder die Festplatten vollgas arbeiten. Varnish hat alles im Hauptspeicher und bedient, soweit er kann, Anfragen.
Cacheanheizer
Ein profaner Cronjob läuft exakt stündlich über die gesamte Site und aktualisiert damit den Varnishcache.
cd /tmp && wget --header "X-Varnish-Nuke:1" --mirror -A '*.html','*.css','*.js','*.png','*.jpg','*.gif' --delete-after http://gnuheidix.de
Bilder sind in meinem Blog nur Schmuckwerk und können getrost ein wenig langsamer sein. Wenn weitere Ressourcen z.B. für den Style benötigt werden, sollten sie an dieser Stelle mit angeheizt werden.
Nginx
Ich habe mich für diesen Webserver entschieden, weil er einfach wesentlich performanter ist als Apache und trotzdem Features wie Rewrites unterstützt. Weiter ist er auch weit verbreitet und dadurch gut getestet. Für Nginx wird wieder eine eigene Konfiguration benötigt. Besonders wichtig ist dabei der S9y-Teil und der FastCGI-Teil. Die Rewrites lassen die URLs gut aussehen und die FastCGI-Konfiguration übergibt einfach alles an php-fpm, was nach PHP riecht.
php-fpm mit XCache
Durch php-fpm ist unter anderem die Überwachung langsamer PHP-Prozesse sehr einfach. Weiter lässt er stets nur so viele Arbeitsprozesse am Leben, um die aktuelle Last gut abzuarbeiten, was Hauptspeicher spart. Mittels XCache muss ein PHP-Arbeitsprozess die Skripte nicht immer von Grund auf verarbeiten. Es wird der OpCode im Hauptspeicher gehalten und kann ohne Parsen direkt ausgeführt werden.
XCache ist schnell eingerichtet. Mir fällt kein Grund ein, XCache auf einem Webserver mit PHP nicht zu aktivieren. Auch das oben umschriebene 0815-Setup würde davon profitieren.
SQLite
Ich erspare meinem Server eine MySQL-Instanz, weil ich das für meine Zwecke für völlig überzogen halte. Diese würde etwa 100MB im Betrieb verheizen, die im Varnish, XCache oder Linux-Dateisystemcache wesentlich besser angelegt sind. S9y unterstützt SQLite als Datenbank, schließlich führt es keine Super-Fancy-Abfragen durch. Die Datenbank liegt als Datei im Dateisystem und wird bei Bedarf von PHP angezogen. Ein Performancevergleich zwischen MySQL und SQLite bei der Anwendung S9y würde mich echt interessieren. Wenn ich viel Zeit habe, messe ich das mal.
Serendipity
Auch S9y habe ich modifiziert. Hauptsächtlich habe ich da an den eingebundenen statischen Ressourcen geschraubt. Dies arbeite ich aber in einem anderen Blogbeitrag auf, weil dieser hier wohl bereits etwas länger geworden ist.
Nachtrag
05.06.2013: Varnish mit mehreren Backends
18.12.2013: Varnish-Konfiguration aktualisiert mit Grace-Mode und Saint-Mode, Cacheanheizer immer ein Cache-Miss für gleichmäßiges Anheizen
12.01.2014: nginx-Konfiguration aktualisiert mit Rewrite-Magic für www-Subdomain; Hinweis: Client-IPs kann man in nginx mit dem Modul HttpRealip extrahieren. (Anleitung)
Kommentare
Rudi Wippermann am :