Die Ressourcen einer Website lassen sich server- und clientseitig auf dem Endgerät der Nutzer zwischenspeichern. Durch das Caching kann die Performance einer Webseite nach dem ersten Abruf, bei dem weiterhin alle Ressourcen geladen werden müssen, maßgeblich verbessert werden [KR13].
Im Bereich des Caching wird zwischen den fünf Faktoren Caching-Dauer, Größe des Cache, Gleichartigkeit, Zugriffshäufigkeit und Invalidierungsstrategie unterschieden. Die Caching-Dauer gibt an, wie lange eine Datei in dem Cache vorgehalten wird, dabei müssen Aktualität, Nutzungsdauer und die Größe des Cache Berücksichtigung finden. Bei dem Abruf einer Webseite werden häufig gleichartige Ressourcen, die eine hohe Zugriffshäufigkeit aufweisen und sich selten ändern, abgerufen. Für die Übertragung dieser Ressourcen ist das Caching vorteilhaft. Mit einer Invalidierungsstrategie wird festgelegt, ab wann die nicht mehr benötigten Daten zu löschen sind [KR13].
Bevor Caching eingesetzt wird, sollten alle anderen Optimierungen ausgeschöpft sein und eine performante Webserverarchitektur vorliegen [KR13]. Nur durch das vorherige Identifizieren und Beheben bestehender Performance-Probleme kann mittels Caching ein Vorteil erzielt werden, der allen Anfragen eine bessere Ladezeit bietet [Ste12].
Clientseitiges Caching
Das Zwischenspeichern von Ressourcen im Browser-Cache des Nutzers sorgt dafür, dass ab dem zweiten Abruf der Webseite weniger Daten übermittelt werden müssen. Folglich reduziert sich die Anzahl der HTTP-Anfragen an den Webserver und damit die Gesamtladezeit der Webseite. Diese Art des Caching empfiehlt sich für statische Daten die sich nicht häufig ändern, wie zum Beispiel Stylesheets, JavaScript-Dateien, PDF-Dokumente oder Bilder. Für dynamische Inhalte und HTML-Dokumente ist auf eine Zwischenspeicherung zu verzichten [Goof]. Ob ein Caching bestimmter Ressourcen erfolgen soll und wie lange die Caching-Dauer ist, wird dem Browser über den Webserver durch das Setzen von HTTP-Headern in der Kommunikation mitgeteilt.
Auf einem Apache Webserver ist dazu die Installation und Aktivierung des Moduls mod_expires erforderlich. Anschließend erfolgt die Definition der Caching-Attribute über eine HTACCESS-Datei im jeweiligen Verzeichnis. Eine Methode zum Caching ist die Nutzung des HTTP-Headers Expires. Mit dessen Hilfe lassen sich Verfallsdaten für das Caching einzelner Ressourcen angeben [KR13], wie anhand der nachfolgenden Konfiguration gezeigt wird.
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType text/html "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
</IfModule>
Expires kann für einzelne Dateitypen definiert werden und sollte maximal ein Jahr betragen. Als Minimum für statische Ressourcen gibt Lara Hogan einen Wert von einem Monat an [Hog15], während Google und Barbara Bermes als Minimalwert eine Woche nennen [Goof] [Ber15].
Eine aktuellere Möglichkeit bietet der HTTP-Header Cache-Control, mit dem eine Zeit in Sekunden als Verfallszeitpunkt anstelle eines Datums festgelegt wird. Nach Ablauf dieser Zeit wird geprüft, ob die gespeicherte Version noch aktuell ist oder eine neuere existiert. Bei der Vergabe eines Datums über Expires muss dieses jedes Mal erneut geprüft werden und eine Synchronisierung der Zeit zwischen Client und Server erfolgen. Cache-Control hebt diese Limitierung auf, es ist somit nicht erforderlich das Datum zu prüfen, sondern nur noch die verbleibenden Sekunden [Sou07].
Für die einzelnen Ressourcen lassen sich bei Cache-Control unter anderem die Attribute max-age, no-cache, public oder private angeben. Während max-age die Cache-Zeit in Sekunden angibt, kann das Caching durch no-cache unterbunden werden. Das Attribut public gibt an, dass eine Ressource als öffentlich anzusehen ist und für alle Nutzer des Endgerätes gilt. Dies bietet sich für Ressourcen an, die häufig aufgerufen werden. Mit Hilfe des Attributes private lassen sich Ressourcen ausschließlich für einen bestimmten Nutzer zwischenspeichern, beispielsweise in geschützten Bereichen die eine Anmeldung erfordern [Ber15].
Anhand des nachfolgenden Beispiels, aus einer HTACCESS-Datei, wird der Aufbau einer Cache-Control Konfiguration dargestellt. Dazu werden Definitionen für Grafiken, Stylesheets und JavaScript-Dateien verwendet sowie die Zeit in Sekunden angegeben.
<ifmodule mod_headers.c>
ExpiresActive On
<filesmatch "\\.(ico|jpe?g|png|gif|swf)$">
Header set Cache-Control "max-age=2592000, public"
</filesmatch>
<filesmatch "\\.(css|js)$">
Header set Cache-Control "max-age=604800, public"
</filesmatch>
</ifmodule>
Sowohl Cache-Control als auch Expires werden als starke Caching-Header bezeichnet, an die sich die Browser bedingungslos halten [Hog15], ohne zu prüfen, ob eine neuere Version der Ressource auf dem Webserver existiert [Goof]. Lara Hogan empfiehlt, aus Sicht der Performanceoptimierung ausschließlich Cache-Control oder Expires zu nutzen und nicht beide Header gleichzeitig [Hog15].
Neben den Headern zur Angabe der Verfallszeitpunkte existieren die schwächeren Header ETag und Last-Modified. Mit diesen wird verglichen, ob die gespeicherte Version mit der auf dem Webserver übereinstimmt oder ob diese zwischenzeitlich geändert wurde. Durch diesen Abgleich wird ein effizientes Aktualisieren der in dem Cache gespeicherten Ressourcen ermöglicht [Goof]. Mit dem ETag wird anhand eines Validierungs-Token, das einem beliebigen Hashwert entspricht, festgestellt, ob eine Datei verändert wurde. Ist der Hashwert unverändert, wird ein HTTP-Statuscode 304 gesendet und die Ressource wird nicht erneut übertragen [Goof]. Der Vorteil gegenüber dem Expires Header ist, dass jede Änderung an einer Ressource festgestellt werden kann und keine veraltete Version im Cache behalten wird [KR13]. Der Last-Modified HTTP-Header prüft die letzte Änderung an einer Ressource mit Hilfe eines zeitbasierten Attributs. Weicht das Datum der letzten Änderung einer Datei von der in dem Browser-Cache hinterlegten Version ab, wird diese erneut geladen. Andernfalls wird ein HTTP-Statuscode 304 gesendet und die lokal zwischengespeicherte Version genutzt [CIW15].
Der Nachteil von Last-Modified und ETag ist, dass für jeden Abgleich eine Anfrage an den Webserver gestellt wird und sich somit die Anzahl der Anfragen nicht reduzieren lässt [KR13]. Google empfiehlt, entweder den ETag oder Last-Modified zu verwenden und nicht beide gleichzeitig [Goof]. Sofern Last-Modified genutzt wird, kann der ETag mit dem folgenden Code-Abschnitt in der HTACCESS-Datei deaktiviert werden.
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
Die aktiven HTTP-Header lassen sich mit den Entwickler-Tools des Browsers Chrome unter den Response Headers in der Network-Ansicht überprüfen (siehe Abbildung 3.2).
Im Rahmen dieser Arbeit wurde durch einen Versuch eine Verbesserung der Ladezeit durch die Nutzung von clientseitigem Caching nachgewiesen. Der zweite Abruf einer Webseite ergab gegenüber dem ersten eine Verbesserung der Ladezeit in Höhe von 36 Prozent, eine Reduzierung der Anfragen um 92 Prozent und eine Verminderung des übertragenen Datenvolumens um 99 Prozent. Die Ermittlung der Ergebnisse in Tabelle 3.1 erfolgte mittels WebPagetest als Median Run bei fünf Durchläufen vom Standort Frankfurt über eine Kabelverbindung mit einer Round Trip Time von 28 Millisekunden.
Tabelle 3.1: Vergleiche zwischen dem ersten Abruf ohne Caching und dem zweiten mit Caching
Messwert | Erster Abruf | Zweiter Abruf | Reduzierung | Verbesserung |
Ladezeit | 1,4 Sekunden | 0,9 Sekunden | 0,5 Sekunden | 36 % |
Start Render | 1,0 Sekunden | 0,8 Sekunden | 0,2 Sekunden | 20 % |
Visually Complete | 1,9 Sekunden | 1,3 Sekunden | 0,6 Sekunden | 32 % |
Speed Index | 1298 | 819 | 479 | 37 % |
Anfragen | 13 | 1 | 12 | 92 % |
Datenvolumen | 419 KB | 4 KB | 415 KB | 99 % |
Die Bedeutung des Caching ist vor allem für mobile Endgeräte aufgrund der Mobilfunknetze recht hoch. Dies lässt sich anhand der Testergebnisse in der nachfolgenden Tabelle 3.2 verdeutlichen. Neben der Gesamtladezeit konnten die durch das Caching erzielten Verbesserungen für Start Render und Visually Complete, im Vergleich zu dem vorherigen Test, nahezu halbiert werden. Die Ermittlung erfolgte erneut vom Standort Frankfurt bei fünf Durchläufen als Median Run mittels WebPagetest. Bei diesem Test wurde zusätzlich die Emulation eines Google Nexus 5, mit einer Datenverbindung über das 3G-Datennetz und einer Round Trip Time von 300 Millisekunden, vorgenommen.
Tabelle 3.2: Verbesserung durch das Caching bei dem Abruf über ein 3G-Datennetz
Messwert | Erster Abruf | Zweiter Abruf | Reduzierung | Verbesserung |
Ladezeit | 4,0 Sekunden | 1,3 Sekunden | 2,7 Sekunden | 67,5 % |
Start Render | 2,6 Sekunden | 1,5 Sekunden | 1,1 Sekunden | 42 % |
Visually Complete | 4,0 Sekunden | 1,5 Sekunden | 2,5 Sekunden | 63 % |
Speed Index | 2838 | 1500 | 1338 | 47 % |
Anfragen | 12 | 1 | 11 | 92 % |
Datenvolumen | 410 KB | 4 KB | 406 KB | 99 % |
Serverseitiges Caching
Während sich das clientseitige Caching im Browser nicht direkt beeinflussen lässt, unter anderem weil der Nutzer das Browser-Caching verbieten kann und die Speicherkapazitäten mobiler Endgeräte begrenzt sind, kann auch ein serverseitiges Caching erfolgen. Häufige Datenbankabfragen oder bereits berechnete Ergebnisse lassen sich im RAM des Webservers oder auf SSDs serverseitig zwischenspeichern, um bessere Zugriffszeiten und damit einhergehend eine schnellere Auslieferung zu erreichen [KR13].
Ein Modul zum Caching von Datenbankabfragen im RAM eines Apache Webservers
ist memchached. Durch eine Zwischenspeicherung der Datenbankinhalte lässt sich der Datenbankserver entlasten. Laut Daniel Kuhn kann in Verbindung mit der Nutzung einer MySQL Datenbank eine Steigerung bis zur zehnfachen Geschwindigkeit der Abfragen erzielt werden, sofern ausreichend Arbeitsspeicher vorhanden ist [KR13].
Mit Reverse-Proxy Caches, die vor den Webserver als Proxy-Server geschaltet werden und die Steuerung der Kommunikation mit dem Client des Nutzers übernehmen, lassen sich Anfragen schneller und effizienter beantworten [KR13]. Häufiger angeforderte statische Ressourcen und die Resultate von Datenbankanfragen werden in dem Reverse-Proxy Cache vorgehalten und bei einer HTTP-Anfrage direkt durch diesen ausgeliefert [CIW15]. Dynamische Inhalte einer Website werden weiterhin über den normalen Webserver abgerufen, jedoch reduziert sich dessen Last durch den Reverse-Proxy [CIW15]. Insbesondere dynamische Websites, die auf Content-Management-Systemen basieren, können von Reverse-Proxys, wie zum Beispiel dem Varnish-Cache, profitieren [KR13]. Durch die Nutzung des Varnish-Cache kann die Performance einer bestehenden Website ohne hohe Kosten gesteigert werden und bietet sich laut Daniel Kuhn als eine gute Kombinationsmöglichkeit zu anderen Caches an [KR13]. Darüber hinaus kann Varnish mit jeder statischen Webseite und jedem CMS genutzt werden, ohne dass eine Integration in das System erforderlich ist [And14]. Lediglich die erstmalige Konfiguration von Varnish ist mit einem höheren Aufwand verbunden [And14].