Caching von Inhalten

Die Ressourcen ein­er Web­site lassen sich serv­er- und client­seit­ig auf dem Endgerät der Nutzer zwis­chen­spe­ich­ern. Durch das Caching kann die Per­for­mance ein­er Web­seite nach dem ersten Abruf, bei dem weit­er­hin alle Ressourcen geladen wer­den müssen, maßge­blich verbessert wer­den [KR13].

Im Bere­ich des Caching wird zwis­chen den fünf Fak­toren Caching-Dauer, Größe des Cache, Gle­ichar­tigkeit, Zugriff­shäu­figkeit und Inva­li­dierungsstrate­gie unter­schieden. Die Caching-Dauer gibt an, wie lange eine Datei in dem Cache vorge­hal­ten wird, dabei müssen Aktu­al­ität, Nutzungs­dauer und die Größe des Cache Berück­sich­ti­gung find­en. Bei dem Abruf ein­er Web­seite wer­den häu­fig gle­ichar­tige Ressourcen, die eine hohe Zugriff­shäu­figkeit aufweisen und sich sel­ten ändern, abgerufen. Für die Über­tra­gung dieser Ressourcen ist das Caching vorteil­haft. Mit ein­er Inva­li­dierungsstrate­gie wird fest­gelegt, ab wann die nicht mehr benötigten Dat­en zu löschen sind [KR13].

Bevor Caching einge­set­zt wird, soll­ten alle anderen Opti­mierun­gen aus­geschöpft sein und eine per­for­mante Web­server­ar­chitek­tur vor­liegen [KR13]. Nur durch das vorherige Iden­ti­fizieren und Beheben beste­hen­der Per­for­mance-Prob­leme kann mit­tels Caching ein Vorteil erzielt wer­den, der allen Anfra­gen eine bessere Ladezeit bietet [Ste12].

Clientseitiges Caching

Das Zwis­chen­spe­ich­ern von Ressourcen im Brows­er-Cache des Nutzers sorgt dafür, dass ab dem zweit­en Abruf der Web­seite weniger Dat­en über­mit­telt wer­den müssen. Fol­glich reduziert sich die Anzahl der HTTP-Anfra­gen an den Web­serv­er und damit die Gesamt­ladezeit der Web­seite. Diese Art des Caching emp­fiehlt sich für sta­tis­che Dat­en die sich nicht häu­fig ändern, wie zum Beispiel Stylesheets, JavaScript-Dateien, PDF-Doku­mente oder Bilder. Für dynamis­che Inhalte und HTML-Doku­mente ist auf eine Zwis­chen­spe­icherung zu verzicht­en [Goof]. Ob ein Caching bes­timmter Ressourcen erfol­gen soll und wie lange die Caching-Dauer ist, wird dem Brows­er über den Web­serv­er durch das Set­zen von HTTP-Head­ern in der Kom­mu­nika­tion mit­geteilt.

Auf einem Apache Web­serv­er ist dazu die Instal­la­tion und Aktivierung des Moduls mod_expires erforder­lich. Anschließend erfol­gt die Def­i­n­i­tion der Caching-Attribute über eine HTAC­CESS-Datei im jew­eili­gen Verze­ich­nis. Eine Meth­ode zum Caching ist die Nutzung des HTTP-Head­ers Expires. Mit dessen Hil­fe lassen sich Ver­falls­dat­en für das Caching einzel­ner Ressourcen angeben [KR13], wie anhand der nach­fol­gen­den Kon­fig­u­ra­tion 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 Date­itypen definiert wer­den und sollte max­i­mal ein Jahr betra­gen. Als Min­i­mum für sta­tis­che Ressourcen gibt Lara Hogan einen Wert von einem Monat an [Hog15], während Google und Bar­bara Bermes als Min­i­mal­w­ert eine Woche nen­nen [Goof] [Ber15].

Eine aktuellere Möglichkeit bietet der HTTP-Head­er Cache-Con­trol, mit dem eine Zeit in Sekun­den als Ver­fall­szeit­punkt anstelle eines Datums fest­gelegt wird. Nach Ablauf dieser Zeit wird geprüft, ob die gespe­icherte Ver­sion noch aktuell ist oder eine neuere existiert. Bei der Ver­gabe eines Datums über Expires muss dieses jedes Mal erneut geprüft wer­den und eine Syn­chro­nisierung der Zeit zwis­chen Client und Serv­er erfol­gen. Cache-Con­trol hebt diese Lim­i­tierung auf, es ist somit nicht erforder­lich das Datum zu prüfen, son­dern nur noch die verbleiben­den Sekun­den [Sou07].

Für die einzel­nen Ressourcen lassen sich bei Cache-Con­trol unter anderem die Attribute max-age, no-cache, pub­lic oder pri­vate angeben. Während max-age die Cache-Zeit in Sekun­den angibt, kann das Caching durch no-cache unter­bun­den wer­den. Das Attrib­ut pub­lic gibt an, dass eine Ressource als öffentlich anzuse­hen ist und für alle Nutzer des Endgerätes gilt. Dies bietet sich für Ressourcen an, die häu­fig aufgerufen wer­den. Mit Hil­fe des Attrib­ut­es pri­vate lassen sich Ressourcen auss­chließlich für einen bes­timmten Nutzer zwis­chen­spe­ich­ern, beispiel­sweise in geschützten Bere­ichen die eine Anmel­dung erfordern [Ber15].

Anhand des nach­fol­gen­den Beispiels, aus ein­er HTAC­CESS-Datei, wird der Auf­bau ein­er Cache-Con­trol Kon­fig­u­ra­tion dargestellt. Dazu wer­den Def­i­n­i­tio­nen für Grafiken, Stylesheets und JavaScript-Dateien ver­wen­det sowie die Zeit in Sekun­den 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-Con­trol als auch Expires wer­den als starke Caching-Head­er beze­ich­net, an die sich die Brows­er bedin­gungs­los hal­ten [Hog15], ohne zu prüfen, ob eine neuere Ver­sion der Ressource auf dem Web­serv­er existiert [Goof]. Lara Hogan emp­fiehlt, aus Sicht der Per­for­manceop­ti­mierung auss­chließlich Cache-Con­trol oder Expires zu nutzen und nicht bei­de Head­er gle­ichzeit­ig [Hog15].

Neben den Head­ern zur Angabe der Ver­fall­szeit­punk­te existieren die schwächeren Head­er ETag und Last-Mod­i­fied. Mit diesen wird ver­glichen, ob die gespe­icherte Ver­sion mit der auf dem Web­serv­er übere­in­stimmt oder ob diese zwis­chen­zeitlich geän­dert wurde. Durch diesen Abgle­ich wird ein effizientes Aktu­al­isieren der in dem Cache gespe­icherten Ressourcen ermöglicht [Goof]. Mit dem ETag wird anhand eines Vali­dierungs-Token, das einem beliebi­gen Hash­w­ert entspricht, fest­gestellt, ob eine Datei verän­dert wurde. Ist der Hash­w­ert unverän­dert, wird ein HTTP-Sta­tus­code 304 gesendet und die Ressource wird nicht erneut über­tra­gen [Goof]. Der Vorteil gegenüber dem Expires Head­er ist, dass jede Änderung an ein­er Ressource fest­gestellt wer­den kann und keine ver­al­tete Ver­sion im Cache behal­ten wird [KR13]. Der Last-Mod­i­fied HTTP-Head­er prüft die let­zte Änderung an ein­er Ressource mit Hil­fe eines zeit­basierten Attrib­uts. Weicht das Datum der let­zten Änderung ein­er Datei von der in dem Brows­er-Cache hin­ter­legten Ver­sion ab, wird diese erneut geladen. Andern­falls wird ein HTTP-Sta­tus­code 304 gesendet und die lokal zwis­chenge­spe­icherte Ver­sion genutzt [CIW15].

Der Nachteil von Last-Mod­i­fied und ETag ist, dass für jeden Abgle­ich eine Anfrage an den Web­serv­er gestellt wird und sich somit die Anzahl der Anfra­gen nicht reduzieren lässt [KR13]. Google emp­fiehlt, entwed­er den ETag oder Last-Mod­i­fied zu ver­wen­den und nicht bei­de gle­ichzeit­ig [Goof]. Sofern Last-Mod­i­fied genutzt wird, kann der ETag mit dem fol­gen­den Code-Abschnitt in der HTAC­CESS-Datei deak­tiviert wer­den.

<IfModule mod_headers.c>
  Header unset ETag
</IfModule>
 
FileETag None

Die aktiv­en HTTP-Head­er lassen sich mit den Entwick­ler-Tools des Browsers Chrome unter den Response Head­ers in der Net­work-Ansicht über­prüfen (siehe Abbil­dung 3.2).

Abbil­dung 3.2: Caching-Angaben der Response Head­er in den Entwick­ler-Tools von Google Chrome

Im Rah­men dieser Arbeit wurde durch einen Ver­such eine Verbesserung der Ladezeit durch die Nutzung von client­seit­igem Caching nachgewiesen. Der zweite Abruf ein­er Web­seite ergab gegenüber dem ersten eine Verbesserung der Ladezeit in Höhe von 36 Prozent, eine Reduzierung der Anfra­gen um 92 Prozent und eine Ver­min­derung des über­tra­ge­nen Daten­vol­u­mens um 99 Prozent. Die Ermit­tlung der Ergeb­nisse in Tabelle 3.1 erfol­gte mit­tels Web­Pagetest als Medi­an Run bei fünf Durch­läufen vom Stan­dort Frank­furt über eine Kabelverbindung mit ein­er Round Trip Time von 28 Mil­lisekun­den.

Tabelle 3.1: Ver­gle­iche zwis­chen dem ersten Abruf ohne Caching und dem zweit­en mit Caching

Mess­wert Erster Abruf Zweit­er Abruf Reduzierung Verbesserung
Ladezeit 1,4 Sekun­den 0,9 Sekun­den 0,5 Sekun­den 36 %
Start Ren­der 1,0 Sekun­den 0,8 Sekun­den 0,2 Sekun­den 20 %
Visu­al­ly Com­plete 1,9 Sekun­den 1,3 Sekun­den 0,6 Sekun­den 32 %
Speed Index 1298 819 479 37 %
Anfra­gen 13 1 12 92 %
Daten­vol­u­men 419 KB 4 KB 415 KB 99 %

Die Bedeu­tung des Caching ist vor allem für mobile Endgeräte auf­grund der Mobil­funknet­ze recht hoch. Dies lässt sich anhand der Testergeb­nisse in der nach­fol­gen­den Tabelle 3.2 verdeut­lichen. Neben der Gesamt­ladezeit kon­nten die durch das Caching erziel­ten Verbesserun­gen für Start Ren­der und Visu­al­ly Com­plete, im Ver­gle­ich zu dem vorheri­gen Test, nahezu hal­biert wer­den. Die Ermit­tlung erfol­gte erneut vom Stan­dort Frank­furt bei fünf Durch­läufen als Medi­an Run mit­tels Web­Pagetest. Bei diesem Test wurde zusät­zlich die Emu­la­tion eines Google Nexus 5, mit ein­er Daten­verbindung über das 3G-Daten­netz und ein­er Round Trip Time von 300 Mil­lisekun­den, vorgenom­men.

Tabelle 3.2: Verbesserung durch das Caching bei dem Abruf über ein 3G-Daten­netz

Mess­wert Erster Abruf Zweit­er Abruf Reduzierung Verbesserung
Ladezeit 4,0 Sekun­den 1,3 Sekun­den 2,7 Sekun­den 67,5 %
Start Ren­der 2,6 Sekun­den 1,5 Sekun­den 1,1 Sekun­den 42 %
Visu­al­ly Com­plete 4,0 Sekun­den 1,5 Sekun­den 2,5 Sekun­den 63 %
Speed Index 2838 1500 1338 47 %
Anfra­gen 12 1 11 92 %
Daten­vol­u­men 410 KB 4 KB 406 KB 99 %

Serverseitiges Caching

Während sich das client­seit­ige Caching im Brows­er nicht direkt bee­in­flussen lässt, unter anderem weil der Nutzer das Brows­er-Caching ver­bi­eten kann und die Spe­icherka­paz­itäten mobil­er Endgeräte begren­zt sind, kann auch ein ser­ver­seit­iges Caching erfol­gen. Häu­fige Daten­bank­abfra­gen oder bere­its berech­nete Ergeb­nisse lassen sich im RAM des Web­servers oder auf SSDs ser­ver­seit­ig zwis­chen­spe­ich­ern, um bessere Zugriff­szeit­en und damit ein­herge­hend eine schnellere Aus­liefer­ung zu erre­ichen [KR13].

Ein Mod­ul zum Caching von Daten­bank­abfra­gen im RAM eines Apache Web­servers
ist mem­chached. Durch eine Zwis­chen­spe­icherung der Daten­bank­in­halte lässt sich der Daten­bankserv­er ent­las­ten. Laut Daniel Kuhn kann in Verbindung mit der Nutzung ein­er MySQL Daten­bank eine Steigerung bis zur zehn­fachen Geschwindigkeit der Abfra­gen erzielt wer­den, sofern aus­re­ichend Arbeitsspe­ich­er vorhan­den ist [KR13].

Mit Reverse-Proxy Caches, die vor den Web­serv­er als Proxy-Serv­er geschal­tet wer­den und die Steuerung der Kom­mu­nika­tion mit dem Client des Nutzers übernehmen, lassen sich Anfra­gen schneller und effizien­ter beant­worten [KR13]. Häu­figer ange­forderte sta­tis­che Ressourcen und die Resul­tate von Daten­bankan­fra­gen wer­den in dem Reverse-Proxy Cache vorge­hal­ten und bei ein­er HTTP-Anfrage direkt durch diesen aus­geliefert [CIW15]. Dynamis­che Inhalte ein­er Web­site wer­den weit­er­hin über den nor­malen Web­serv­er abgerufen, jedoch reduziert sich dessen Last durch den Reverse-Proxy [CIW15]. Ins­beson­dere dynamis­che Web­sites, die auf Con­tent-Man­age­ment-Sys­te­men basieren, kön­nen von Reverse-Prox­ys, wie zum Beispiel dem Var­nish-Cache, prof­i­tieren [KR13]. Durch die Nutzung des Var­nish-Cache kann die Per­for­mance ein­er beste­hen­den Web­site ohne hohe Kosten gesteigert wer­den und bietet sich laut Daniel Kuhn als eine gute Kom­bi­na­tion­s­möglichkeit zu anderen Caches an [KR13]. Darüber hin­aus kann Var­nish mit jed­er sta­tis­chen Web­seite und jedem CMS genutzt wer­den, ohne dass eine Inte­gra­tion in das Sys­tem erforder­lich ist [And14]. Lediglich die erst­ma­lige Kon­fig­u­ra­tion von Var­nish ist mit einem höheren Aufwand ver­bun­den [And14].