Mit Apache's mod_cache auf Debian Lenny Daten zwischenspeichern

Caching With Apache's mod_cache On Debian Lenny

Version 1.0

Autor: Falko Timme

Folge mir auf Twitter!


Diese Anleitung erklärt wie man seine Webseiteninhalte zwischenspeichern kann, indem man Apaches mod_cache auf einem Debian Lenny benutzt. Wenn man eine viel besuchte, dynamische Webseite hat, das viele Datenbank-Anfragen bei jedem Zugriff generiert, kommt es zu einer erhöhten Serverauslastung. Diese kann erheblich gesenkt werden, indem die Inhalte für einige Minuten oder mehr zwischengespeichert werden, abhängig davon wie häufig der Webseiteninhalt aktualisiert wird.

Diese Anleitung ist ohne jede Gewähr.

1 Vorbemerkung

Ich gehe davon aus, dass Du bereits eine funktionierende Apache2 Installation hast (Apache 2.2.x - für die Vorabversionen wird cache-Mod allerdings als exeprimentell eingestuft) aus den Debian Paketen. Wenn die Apache Version in den Debian Paketen die 2.2.9 sein sollte, ist das perfekt.

Ich verwende hier den Dokumenten root /var/www für meinen vhost Test. Bitte passe dieses an, sollte Dein Dokument root anders sein.

2 mod_cache aktivieren

mod_cache hat zwei Untermodule, die den Zwischenspeicher verwalten: mod_disk_cache (um Inhalte auf der Festplatte zu speichern) und mod_mem_cache (um Inhalte im Cahce zu speichern, was schneller als die Festplatten-Version ist). Nachdem Du Dich für eine der Methoden entschieden hast, gehe weiter zu Kapitel 2.1 (mod_disk_cache) oder 2.2 (mod_mem_cache).

2.1 mod_disk_cache

Die mod_disk_cache Konfiguration ist in /etc/apache2/mods-available/disk_cache.conf gespeichert, also editieren wir diese:

vi /etc/apache2/mods-available/disk_cache.conf

Die Zeile CacheEnable disk / unbedingt auskommentieren, so daß die minimale Konfiguration folgendermaßen aussieht:
<IfModule mod_disk_cache.c>
# cache cleaning is done by htcacheclean, which can be configured in # /etc/default/apache2 # # For further information, see the comments in that file, # /usr/share/doc/apache2.2-common/README.Debian, and the htcacheclean(8) # man page. # This path must be the same as the one in /etc/default/apache2 CacheRoot /var/cache/apache2/mod_disk_cache # This will also cache local documents. It usually makes more sense to # put this into the configuration for just one virtual host. CacheEnable disk / CacheDirLevels 5 CacheDirLength 3 </IfModule>
Du findest die Erklärungen für diese und andere  Konfigurationsoptionen auf http://httpd.apache.org/docs/2.2/mod/mod_disk_cache.html.

Nun können wir mod_cache und mod_disk_cache aktivieren:

a2enmod cache

a2enmod disk_cache

/etc/init.d/apache2 restart

Um sicher zu sein, dass unser Cache Verzeichnis  /var/cache/apache2/mod_disk_cache mit der Zeit nicht zu voll wird, müssen wir es mit dem htcacheclean Befehl zwischendurch aufräumen bzw. leeren. Dieses Befehl ist Teil des apache2-utils Pakets, welches wir folgendermaßen installieren:

aptitude install apache2-utils

Hiernach können wir htcacheclean als daemon starten:

htcacheclean -d30 -n -t -p /var/cache/apache2/mod_disk_cache -l 100M -i

Das wird den Zwischenspeicherverzeichnis (cache) alle 30 Minuten leeren und damit dafür sorgen, dass er nicht größer als 100 MB wird. Um mehr über htcacheclean zu erfahren, schau Dir dieses an:

man htcacheclean

Damit htcacheclean nicht jedesmal beim (Neu-)Start manuell gestartet werden muss,editieren wir die Datei /etc/rc.local...

vi /etc/rc.local

... und fügen folgende Zeile hinzu, genau vor der  exit 0 Zeile:
[...]
/usr/sbin/htcacheclean -d30 -n -t -p /var/cache/apache2/mod_disk_cache -l 100M -i [...]
Dieser Befehl wird htcacheclean automatisch starten, jedesmal wenn der Server (neu-)startet.

2.2 mod_mem_cache

Die Konfiguration von mod_mem_cache findet man in /etc/apache2/mods-available/mem_cache.conf:

vi /etc/apache2/mods-available/mem_cache.conf

<IfModule mod_mem_cache.c>
CacheEnable mem / MCacheSize 4096 MCacheMaxObjectCount 100 MCacheMinObjectSize 1 MCacheMaxObjectSize 2048 </IfModule>
Das ist die Standardkonfiguration; wenn Du möchtest, kannst Du diese ändern. Eine Liste der Konfigurationsbefehle für mod_mem_cache findest Du hier: http://httpd.apache.org/docs/2.2/mod/mod_mem_cache.html.

Nun aktivieren mod_cache und mod_mem_cache wie folgt:

a2enmod cache

a2enmod mem_cache

/etc/init.d/apache2 restart

Das ist schon fast, aber nur fast alles! Mit mod_mem_cache wirst Du nie wieder irgendwelche Verzeichnisse aufräumen müssen.

3 Testen

Leider hat mod_cache keinerlei Funktion, die eventuelle Fehlermeldungen u.ä. protokolliert, weshalb man nicht sehen kann ob mod_cache überhaupt funktioniert.  Daher erstelle ich eine kleine PHP Test- Datei /var/www/cachetest.php, das HTTP Headers sendet, die mod_cache befehlen die Datei für 300 Sekunden zwischenzuspeichern und dann einfach die Zeit ausgibt:

vi /var/www/cachetest.php

<?php
header("Cache-Control: must-revalidate, max-age=300"); header("Vary: Accept-Encoding"); echo time()."<br>"; ?>
Rufe nun die Datei im Brwoser auf - es sollte die aktuelle Zeit anzeigen. Dann klicke in die Adressleiste des Browsers und drücke ENTER so daß die Seite noch einmal geladen wird - drücke nicht F5 oder "Neu laden", das würde nur eine neue Kopie von dem Server ausgeben anstatt dem Zwischenspeicher! Wenn alles funktioniert, so solltest Du immer noch die alte, zwischengespeicherte Zeit sehen.Wenn Du 300 Sekunden wartest, solltest Du hingegen eine neue Ausgabe vom Server bekommen anstatt des Zwischenspeichers.

4 HTTP Header

Das sogenannte cachen bzw. Zwischenspeichern funktioniert nicht auf Anhieb. Du musst Deine Webapplikation so ändern, daß zwischenspeichern ermöglicht wird. Vielleicht unterstützt Deine Webapplikation cachen bzw. zwischenspeichern bereits - bitte schau Dir dazu die entsprechende Dokumentation der Anwendung an. mod_cache wird Webseiten nur dann zwischenspeichern wenn es im HTTP Header  der Webseiten, die von Deiner Webapllikation gesendet werden, als Anweisung drin steht.

Hier sind einige Besipiele eines Headers, das mod_cache sagt nicht zwischenzuspeichern bzw. zu cachen:
  • Expires Header mit einem Datum in der Vergangenheit "Expires: Sun, 19 Nov 1978 05:00:00 GMT"
  • Einige Cache-Control Header: "Cache-Control: no-store, no-cache, must-revalidate" oder "Cache-Control: must-revalidate, max-age=0"
  • Set-Cookie Header: Die Seite wird nicht zwischengespeichert wenn kein Cookie gesetzt wurde.
Sollest Du also mit mod_cache zwischenspeichern wollen, ändere die Applikation so ab dass sie solche Header nicht mehr sendet.

Soll mod_cache deine Seiten zwischenspeichern, kannst Du einen Expires Header mit einem Datum in der Zukunft setzen, allerdings ist die empfohlene Variante die Nutzung von max-age:

"Cache-Control: must-revalidate, max-age=300"

Das sagt mod_cache daß es die Seite für 300 Sekunden (max-age) zwischenspeichern bzw. cachen soll  - leider kennt mod_cache die Option s-maxage nicht,  (siehe http://www.mnot.net/cache_docs/#CACHE-CONTROL), weshalb wir die max-age Option nutzen müssen (Diese sagt auch Deinem Browser dass er zwischenspeichern soll - bitte daran denken falls Fehlermeldungen kommen!). Wenn mod_cache die s-maxage Option kennen würde, könnten wir "Cache-Control: must-revalidate, max-age=0, s-maxage=300" benutzen, welches mod_cache, aber nicht dem Browser, sagt, die Seite zwischenzuspeichern.

Natürlich ist dieser Header nutzlos, wenn gleichzeitig ein Header gesendet wird, der nicht zwischenspeichert!  (Expires in der Vergangenheit, Set-Cookie, etc.) !

Ein anderer unentbehrlicher Header zum cachen ist dieser:

"Vary: Accept-Encoding"

Der bewirkt daß mod_cache zwei Kopien von jeder gecachten Seite speichert, eine als .gzip komrimiert, die andere unkomprimiert, so daß die richtige Version ausgeliefert werden kann, je nach dem Programm dass es anfordert. Einige können die .gzip Version nicht verwenden, so daß es eben auch eine nicht komprimierte Version geben muss.

Und hier ist die Zusammenfassung: Benutze beide folgende Header wenn Du mit mod_cache zwischenspeichern möchtest:

"Cache-Control: must-revalidate, max-age=300"

"Vary: Accept-Encoding"

und stelle sicher daß keine Expires mit einem Datum in der Vergangenheit, Cookies oder anderes gesendet werden.

Wenn Deine Applikation in PHP geschrieben ist, kannst Du den PHP  header() function verwenden um die HTTP Header auszusenden, wie beispielsweise hier:

header("Cache-Control: must-revalidate, max-age=300");

header("Vary: Accept-Encoding");

Diese Seite ist eine Pflicht wenn Du mehr über HTTP Header und Zwischenspeicher bzw. Chache wissen möchtest: http://www.mnot.net/cache_docs/

5 Links