Zwischenspeichern der Index-Seiten für Gäste
Wie man die Index-Seiten zwischenspeichern und so die Datenbank entlasten kann.
Bei Aufruf der Foren-Übersicht (index.php) und der Forenansichten (viewforum.php) werden jeweils einige Anfragen an die Datenbank geschickt und aus den Ergebnissen die Seiten zusammengestellt.
Dies geschieht bei jedem Aufruf einer dieser Seiten, egal ob sie von einem Gast oder einem eingeloggten Benutzer aufgerufen wird. Und weil wir zu normalen Tageszeiten fast 30 Gäste online haben, ist das eine Stelle, an der man gut ansetzen kann, um den Server etwas zu entlassten.
Daher folgende Idee: Gäste müssen nicht immer alles in 'Echtzeit' sehen, eine 'Verspätung' von zwei Minuten können sie verkraften. Also cachen wir die index.php und die viewforum.php für Gäste und erneuern den Cache alle zwei Minuten.
Dazu benötigen wir ein Skript (ein Unix-Shell-Skript, um genau zu sein), das später per Cron (Ich beschreibe hier die Implementierung auf phpBB.de, und da wir auf einem Linux-Server sitzen, benutzen wir cron.) aufgerufen wird, das seinerseits wget benutzt, und eine kleine Änderung in der index.php sowie der viewforum.php.
Doch zunächst brauchen wir zwei Verzeichnisse für die zwischengespeicherten Dateien. Ich habe im phpBB-Verzeichnis ein Verzeichnis 'wget' erstellt und darin ein Verzeichnis 'temp'. Das Skript wird dafür sorgen, das die Ausgaben von wget in 'temp' landen und von dort eine Etage aufwärts nach 'wget' verschoben werden. Würden wir nur ein Verzeichnis benutzen, müssten wir die Dateien jeweils löschen und neu erstellen lassen, was dazu führen kann, das ein Benutzer gerade in dem Moment, wo die Dateien schon gelöscht, aber die neuen noch nicht erstellt sind, auf sie zugreifen möchte und sich eine Fehlermeldung einhandelt.
Code: | #!/bin/sh
cd /Pfad/zu/phpbb.de/wget/temp
rm *.html
for i in `cat ../urls.list`; do
# möglicherweise defekte vorherige downloads löschen
rm -f *.html
wget $i -E -U Cache-Skript && mv *.html ../
done; |
Das ganze wird im 'wget'-Verzeichnis als 'cache.sh' gespeichert und mittels chmod a+x cache.sh ausführbar gemacht.
Wir wechseln in das 'temp'-Verzeichnis und löschen dort alle HTML-Dateien. Dann benutzen wir eine vorbereitete Liste von URLs, die in der Datei 'urls.list' im 'wget'-Verzeichnis gespeichert sind. Hier die urls.list für phpBB.de:
Code: | http://www.phpbb.de/index.php
http://www.phpbb.de/viewforum.php?f=1
http://www.phpbb.de/viewforum.php?f=4
http://www.phpbb.de/viewforum.php?f=6
http://www.phpbb.de/viewforum.php?f=8
http://www.phpbb.de/viewforum.php?f=9
http://www.phpbb.de/viewforum.php?f=18
http://www.phpbb.de/viewforum.php?f=12
http://www.phpbb.de/viewforum.php?f=13
http://www.phpbb.de/viewforum.php?f=15
http://www.phpbb.de/viewforum.php?f=16
http://www.phpbb.de/viewforum.php?f=19
http://www.phpbb.de/viewforum.php?f=34
http://www.phpbb.de/viewforum.php?f=33
http://www.phpbb.de/viewforum.php?f=35 |
All diese URLs ruft wget (das also wie ein Browser arbeitet, mit dem Unterschied, das es die Seiten nicht grafisch darstellt, sondern direkt abspeichert) auf und speichert die Ausgabe. Der Parameter -U Cache-Skript sorgt dafür, das sich wget dem Webserver gegenüber als 'Cache-Skript' ausgeben soll. Warum dies nötig ist, sehen wir weiter unten.
Schließlich verschieben wir diese Dateien ins eigentliche Cache-Verzeichnis 'wget'.
Jetzt müssen wir diesen Vorgang nur noch automatisieren, damit wir alle 2 Minuten neue, frische Cache-Dateien haben. Dazu benutzen wir Cron und fügen in unsere Crontab die Zeile
Code: | */2 * * * * /Pfad/zu/phpbb.de/wget/cache.sh |
ein. Ist das Forum nicht so aktiv, kann man dieses Intervall auch auf fünf oder gar zehn Minten erhöhen, wobei man sich das Ganze dann eigentlich sowieso sparen kann. Umgekehrt kann man das Intervall auf eine Minute festlegen, wobei sich dies nur bei noch aktiveren Foren als phpBB lohnen würde.
So, der Cache ist aufgesetzt, jetzt müssen wir das nur noch phpBB sagen.
In der index.php fügen wir dazu direkt nach Code: | //
// Start session management
//
$userdata = session_pagestart($user_ip, PAGE_INDEX);
init_userprefs($userdata);
//
// End session management
//
| diesen Code ein: Code: | if (!$userdata['session_logged_in'] && $_SERVER['HTTP_USER_AGENT'] != 'Cache-Skript')
{
readfile('/Pfad/zu/phpbb.de/wget/index.php.html');
exit;
}
|
Hier begegnet uns 'Cache-Skript' wieder. Wir benutzen diese Kennung, um zwischen normalen Gästen und unseren Cache-Skript zu unterscheiden. Würden wir nur auf $userdata['session_logged_in'] prüfen, könnte unser Cache-Skript nicht funktionieren, da phpBB dann das Cache-Skript wie einen normalen Gast behandeln würde und ihm statt einer frischen Ansicht die eigenen Cache-Dateien anzeigen würde. Klassischer Schuß in den Fuß
Nun noch das gleiche in der viewforum.php. Direkt hinter dem Session-Management wird dies eingefügt: Code: | if (!$userdata['session_logged_in'] && $_SERVER['HTTP_USER_AGENT'] != 'Cache-Skript' && $start == 0 && $markread == '')
{
readfile('/Pfad/zu/phpbb.de/wget/viewforum.php?f=' . $forum_id . '.html');
exit;
}
|
Die Prüfung auf $start == 0 && $mark_read == '' stellt sicher, das Gäste weiterhin im Forum blättern können.
Mittlerweile sollten sich im 'wget'-Verzeichnis bereits die ersten Cache-Dateien befinden. Wenn nicht, führen wie die cache.sh einmal per Hand aus.
Von jetzt an bekommen Gäste nur noch astreines HTML geliefert und das Forum spart sich einige Dutzend SQL-Anfragen, Template-Parsings, ...
PS: Man könnte sich überlegen, den Aufruf der Caches in der index.php und der viewforum.php direkt an den Anfang zustellen. Man müsste dann direkt auf Cookis und/oder URL-Parameter prüfen und könnte phpBB vollständig umgehen. Andererseits würden dann zum Beispiel Bans nicht mehr greifen.
Weiterhin könnte man die Unterscheidung Cache-Skript oder Gast auch über die IP lösen, statt wie hier mittels User-Agent. Der Phantasie sind da keine Grenzen gesetzt. BTW, wie man den User-Agent nun nennt, ob 'Cache-Skript' oder 'Oma Krause' ist schnurz.
|