Making of wien.info – Performance und Caching

Im Juni 2009 führte WIENFLUSS im Auftrag von WienTourismus den Relaunch der offiziellen Wiener Tourismuswebsite wien.info durch. In einer losen Artikelserie wollen wir ein wenig die Hintergründe und Erfahrungen aus diesem Projekt beleuchten.

Damit man als BesucherIn einer Website diese als hinreichend schnell wahrnimmt – d.h. eigentlich nimmt man bewusst meist die Geschwindigkeit einer Website dann wahr, wenn sie zu langsam ist – sind ein Bündel an Faktoren verantwortlich. Im wesentlichen geht’s um effiziente serverseitige Auslieferung der Daten, eine performante Übertragung zum Client und einen flotten Seitenaufbau im Browser.

Analyse-Tools

Für die Analyse gibt es einige feine und kostenlose Tools, die darüber hinaus auch sehr lehrreich sind, nicht zuletzt aufgrund der begleitenden Dokumentation: Im Firebug gibt’s das Net-Panel, das eine gute Übersicht über Response-Code und HTTP-Header sowie eine grafische Darstellung der zeitlichen Verteilung des Ladevorgangs einer Seite bietet.

Eine etwas umfangreichere Alternative dazu bietet der Fiddler, eine Art HTTP-Debugger, der die Rolle eines lokal installierten Proxies übernimmt und den gesamten HTTP-Traffic dokumentiert.

Yslow und Page Speed sind Firebug Plugins, mit denen Seiten nach unterschiedlichen Gesichtspunkten analysiert und gleich entsprechende Empfehlungen ausgesprochen werden.

HTTP-Verbindungen

Eine der wichtigsten Maßnahmen – abgesehen vom Caching, auf das wir später noch zurückkommen – ist die Anzahl der HTTP-Requests einer Seite minimal zu halten. Jede Verbindung muss nicht nur eigens aufgebaut werden, sondern dazu kommen auch jedes Mal Request- und Response-Header sowie alle Cookies mit.

Eine höchst ineffiziente Angelegenheit, wenn man bedenkt, dass hundert Requests bei einer einzigen Seite heute keine Seltenheit sind. Das betrifft in erster Linie die eingebundenen CSS- und Javascript-Files sowie layout-relevante Bilder (zumeist Background-Images).

Was die beiden ersten betrifft, gibt’s mehrere Möglichkeiten damit umzugehen. Die eine Option ist, dass man immer nur jene Files lädt, die auf der entsprechenden Seite tatsächlich gebraucht werden. Das kann schnell mal ziemlich kompliziert werden und der tatsächliche Einspareffekt ist dabei oft gering – daher aus unserer Sicht keine geeignete Strategie.

Die bessere Alternative ist, CSS- und Javascript-Files jeweils zu einem File zusammenzufassen. Theoretisch bietet Plone die Möglichkeit das automatisch durchzuführen. Für wien.info war das aber keine Option, da der eingebaute Mechanismus für unsere Zwecke nicht flexibel genug war. Insgesamt konnten wir aber durch diese Maßnahme die Anzahl der CSS-Files pro Seite von 13 auf 3 und jene der JS-Files von 16 auf 4 reduzieren.

Die Anzahl der Layout-Bilder ließe sich theoretisch durch sogenannte Image Sprites reduzieren. Dabei werden mehrere Background-Bilder in einem File zusammengefasst und bei der Einbindung mittels CSS durch horizontale und vertikale Offsets so verschoben, dass an der jeweiligen Stelle nur der gewünschte Teil sichtbar ist. Das bekannteste Beispiel dafür ist das Sprite auf der Google Suchergebnisseite, das nur etwas über 5kb groß ist, aber alle Googleschriftzüge, Icons und Buttonhintergründe der Seite zusammenfasst.

Verwendet man wie wir ein elastisches Layout, das mit der Schriftgröße skaliert, macht das die Verwendung von Image Sprites in vielen Fällen unmöglich, da man oft nicht weiß, wie groß der dargestellte Ausschnitt beim User tatsächlich ist. Damit besteht die Gefahr, dass benachbarte Bilder zum Vorschein kommen, wo sie eigentlich verborgen bleiben sollten.

Caching

Der Cache ist ein Puffer-Speicher, der einen schnellen Zugriff auf gewisse Daten erlaubt, ohne dass diese nochmals neu abgearbeitet oder geladen werden müssen. Klarerweise muss darauf geachtet werden, dass dabei keine veralteten Elemente angezeigt oder verwendet werden.
Layout-spezifische Elemente (CSS, Javascript, Background-Images) haben dabei natürlich eine wesentlich längere „Lebensdauer“, typischerweise ein Monat oder mehr, und inhaltsrelevante Elemente (die HTML-Seite selbst, Bilder aus dem Inhalt) sollten so lange gecacht werden, wie aus redaktioneller Sicht gerade noch akzeptabel.

Für wien.info haben wir die Cachingzeiten von CSS, Javascript und Layoutbildern mit 32 Tagen, jene von Inhaltsbildern mit vier Stunden und die der Inhalte (HTML-Seiten) mit einer Stunde festgelegt. Innerhalb dieser besteht die Möglichkeit, dass der User „veraltete“ Inhalte sieht, das ist der Preis für Caching.

Beim Content ist das aufgrund der relativ kurzen Lebensdauer akzeptabel, beim Design kann das zum Problem werden, wenn in der Zwischenzeit neue Features ausgerollt oder Bugs behoben wurden. Hier muss kann man sich aber damit behelfen, indem man z.B. den geänderten Javascript- und CSS-Files jeweils einen Timestamp in den Dateinamen gibt. In der Anfangsphase durch die relativ häufigen Änderungen mühsam, aber später wenn die Codebase der Website stabiler wird, kaum der Rede wert.

Client vs. Server

Grundsätzlich ist zwischen dem Caching auf Browser-Ebene und jenem auf Server-Ebene zu unterscheiden.
Das Caching auf Browser-Seite bestimmt, welche Dateien aus dem lokalen Puffer-Speicher bezogen werden können und welche vom Server angefordert werden müssen.

Festgelegt wird dies im HTTP-Response Header durch Expires oder Cache-Control: max-age sowie Last-Modified oder ETag.

Expires bzw. Cache-Control sind unbedingte Caching-Controls, die den Browser innerhalb der angegebenen Lebensdauer gar nicht nachfragen lassen, ob sich die Inhalte am Server verändert haben; sehr effizient also aus Sicht der Performance.
Der Caching-relevante Teil des HTTP-Responses für ein Hintergrundbild sieht z.B. so aus:

Expires: Mon, 19 Oct 2009 14:38:17 GMT
X-Caching-Policy: Cache Resource
Last-Modified: Fri, 03 Jul 2009 18:00:52 GMT
Cache-Control: max-age=2764800,public

Auf der Server-Seite ist ein Caching-Proxy (Varnish) im Einsatz. Der soll verhindern, dass das CMS durch die vielen Requests in die Knie gezwungen wird. Nur Einträge, die „abgelaufen“ sind, werden an das CMS weitergereicht, alle anderen werden aus dem Cache des Proxies bedient. Die Trefferquote für den Pufferspeicher beträgt mit den oben dargestellten Lebenszeiten von Dokumenten durchschnittlich knapp über 90%. Ein durchaus zufriedenstellender Wert. Auch nach einem Restart geht der Wert in etwa einer halben Stunde wieder auf dieses Niveau hoch.

Personalisierung, Geotargeting und Caching

Eine Voraussetzung für effektives Caching ist, dass die auszuliefernden Inhalte innerhalb einer Seite gleichbleibend sind. Das stimmt bei wien.info soweit der Seitencontent, die Navigation und einige andere Seitenelemente betroffen sind.

Andere Seiteninhalte werden aber in Abhängigkeit von den BesucherInnen ausgeliefert. Promotions richten sich z.B. ausschließlich an gewisse Zielmärkte, die aber nicht immer mit der jeweiligen Sprache identisch sind. Das heißt, mit Hilfe der IP-Adresse wird die Geo-Position des Users (Land) ermittelt und die Auslieferung der jeweiligen Promotion getriggert oder auch nicht.

Abgesehen vom Geotargeting bietet wien.info auch personalisierte Inhalte: die Zusammenstellung eines persönlichen Reiseplans und Empfehlungen in Abhängigkeit der persönlichen Interessen. D.h. auch eingeloggte User erhalten etwas andere Inhalte ausgeliefert als jene, die anonym surfen.

Insgesamt bleibt trotz allem der weitaus überwiegende Teil einer Seite über alle Requests gleich. Es macht daher Sinn, im gegebenen Fall nur die User-abhängigen Inhalte vom Server nachzufordern und den Großteil der Seite aus dem Cache auszuliefern. Möglich wird dies durch den Einsatz von so genannten Edge Side Includes (ESI), einer Markupsprache ähnlich HTML, die durch den Caching-Proxy interpretiert wird und für die Nachforderung und Einbettung der personalisierten Inhalte verantwortlich ist.

Die Einbettung der ESIs ist ziemlich simpel, in dem man ins HTML, das vom CMS an den Caching-Proxy ausgeliefert wird, folgenden Code einfügt.

Die Includes selbst sollen in den meisten Fällen nicht gecacht werden. Das verhindert man in der Konfiguration vom Varnish Caching-Proxy.
Geotargeted Promotions werden nie gecacht – sie werden aufgrund der Client-IP vom CMS ausgeliefert:

if (req.url ~ "render-include-promotion$" ||
req.url ~ "render-include-headerpromotion$") {
// Never cache the includes for promotions
return (pass); }

Alle anderen Promotions werden erst gar nicht mit ESI-Tags ausgeliefert und daher ganz normal wie jeder andere Content gecacht.
Der personalisierte myVienna-Bereich einer Seite wird nicht gecacht, wenn die User angemeldet sind (die Anmeldung wird in einem Cookie gespeichert):

if ((req.http.Cookie ~ "user")) {
if (req.url ~ "render-include-myvienna$") {
// Don't cache myVienna-Includes for logged in users
return (pass);
}
}

Ein Gedanke zu „Making of wien.info – Performance und Caching

Kommentare sind geschlossen.