Ausgaben in Cache speichern

Viele auf PHP basierende Projekte generieren mit einer PHP-Datei viele Ausgabe-Seiten. Sei es in einem Onlineshop, in denen auf der Detailseite die Daten aus einer Datenbank geholt und vom Script an die richtige Stelle platziert werden oder ein Blog, bei dem im Prinzip genau das gleiche passiert: Eine Datei wird mit einem eindeutigen Parameter aufgerufen und über diesen Parameter können aus der Datenbank die nötigen Inhalte geladen und präsentiert werden. Die fertig zusammengebaute Seite wird dann zurück an den Client geschickt.
Wenn man nun Seiten hat, die sich recht selten ändern (beispielsweise die Detailseite eines bestimmten Artikels in einem Shop), wäre es ja nun möglich die einmal erzeugte Ausgabe als HTML-Datei zu speichern, damit beim nächsten Aufruf die Seite nicht wieder umständlich zusammengebaut werden muss, sondern einfach nur die HTML-Datei geladen werden muss. Und genau das nennt ist Caching.

Anwendungsgebiete sind vor allem Detailseiten, die relativ selten geändert werden und über einen Permalink erreichbar sind. Denkbar schlecht geeignet ist Caching für Seiten, die sich recht häufig ändern, wie beispielsweise die neuesten Artikel einer Website, denn dort soll ja – sobald ein neuer Artikel eingestellt wird – dieser auch auftauchen.

Erstmal haben wir unsere PHP-Seite, die irgendwelche Ausgaben ausspuckt:

for($i=0;$i<1000;$i++) {
  echo $i." Hallo Welt, ich bin ein PHP-String, der auf dem Bildschirm ausgegeben wird.<br />";
}

Dieses Script ist nicht sehr sinnvoll, das braucht sie aber auch gar nicht, um das Konzept zu erklären. Es wird 1000 mal der Satz ausgegeben. Dieser Satz steht stellvertretend für die vielen Ausgaben auf einer „richtigen“ Website.

Um die gesamten Ausgaben einer PHP-Anwendung zu erhalten, müssen wir die Ausgabe puffern. Das geschieht durch folgende Erweiterung:

ob_start();
for($i=0;$i<1000;$i++) {
  echo $i." Hallo Welt, ich bin ein PHP-String, der auf dem Bildschirm ausgegeben wird.<br />";
}
 
$content = ob_get_clean();
echo $content;

ob_start weißt PHP an, alle Ausgaben in den internen Puffer zu schreiben und ob_get_clean liefert all diese Ausgaben in einem String zurück und leert den Puffer. Diesen String können wir dann ausgeben. Das ist allerdings erstmal das Puffern und noch nicht das Cachen (sorry für diese Denglisch-Wörter 🙂 ).
Für das Caching muss die Ausgabe nun in eine statische Datei gespeichert werden. Dazu erweitern wir das Script:

ob_start();
for($i=0;$i<1000;$i++) {
  echo $i." Hallo Welt, ich bin ein PHP-String, der auf dem Bildschirm ausgegeben wird.<br />";
}
 
$content = ob_get_clean();
$fh = fopen("cache".$_SERVER['PHP_SELF'].".html","w");
fputs($fh, $content);
fclose($fh);
echo $content;

Wir öffnen ein File-Handle auf die gewünschte Datei. Diese wird erzeugt, falls sie nicht existiert und ansonsten überschrieben (Flag „w“ in der fopen-Funktion). Sie bekommt den Dateinamen der aktuellen PHP-Datei – hier kann man aber hineinschreiben, was man will und liegt im (vorher per Hand erzeugten) Verzeichnis cache. Das Wichtigste bei der Vergabe des Dateinamens ist, dass es keine Überschneidungen mit anderen Dateien gibt. Geeignet wäre beispielsweise auch – wenn die PHP-Datei mit einer ID aufgerufen wird – den Dateinamen „cache_“.$_GET[‚id‘].“.html“ zu nehmen, da jede ID der einzelnen Artikel ja eindeutig sein sollte – Stichwort Primärschlüssel in der Datenbank.

Das bloße Speichern hilft natürlich noch nix, denn das würde eher mehr Laufzeit verbrauchen als vorher (und dazu noch zusätzlichen Speicherplatz belegen). Beim nächsten Aufruf sollte nicht das PHP-Script abgearbeitet werden sondern die gespeicherte Datei einfach geladen und ausgegeben werden. Damit aber Aktualisierungen, die ab und zu ja doch vorkommen, trotzdem einen Effekt haben, könnte man entweder den Cache in regelmäßigen Abständen löschen (bei uns alle Dateien im Verzeichnis cache). Oder aber man prüft, wann die HTML-Datei das letzte mal bearbeitet wurde und falls das länger her ist als ein bestimmter Zeitabstand, lässt man doch PHP arbeiten, damit der Stand in der HTML-Datei aktualisiert wird.

if(file_exists("cache".$_SERVER['PHP_SELF'].".html") && time()-filemtime("cache".$_SERVER['PHP_SELF'].".html")<24*3600) {
  echo file_get_contents("cache".$_SERVER['PHP_SELF'].".html");
  exit();
}
ob_start();
for($i=0;$i<1000;$i++) {
  echo $i." Hallo Welt, ich bin ein PHP-String, der auf dem Bildschirm ausgegeben wird.<br />";
}
 
$content = ob_get_clean();
$fh = fopen("cache".$_SERVER['PHP_SELF'].".html","w");
fputs($fh, $content);
fclose($fh);
echo $content;

Nun prüft PHP am Anfang, ob eine Datei im Cache existiert, die auf die Anforderung passt. Falls es eine findet, prüft es zusätzlich, ob die Änderungszeit länger als 1 Tag zurückliegt. Sind beide Bedingungen erfüllt, wird die Datei möglichst schnell eingelesen und ausgegeben. Anschließend wird die weitere Verarbeitung des Scripts mit exit() verhindert, denn wir haben ja alles, was wir wollten.

Im Vergleich mit der normalen Ausgabe verhalten sich die Laufzeiten folgendermaßen:

Datei Gesamtlaufzeit durchschnittliche Laufzeit pro Durchlauf Verhältnis zur schnellsten Variante
result_ausgabe_
cache.php
31.94712 s 3.109 ms 100 %
result_ausgabe_
normal.php
38.875900 s 3.888 ms 125 % (+ 25%)

Die gecachte Version ist also in diesem Fall um 25 % schneller. Das Einlesen der HTML-Datei kostet zwar eine gewisse Zeit, allerdings kostet das Durcharbeiten der Schleife wesentlich mehr Zeit. Das ist auch in der Praxis so (teilweise noch größerer Abstand), denn dort müsste erst eine (wahrscheinlicher sind mehrere) Datenbankabfrage(n) gemacht und ausgewertet werden, die recht viel Zeit verschlingt. Und außerdem können umfangreiche Berechnungen oder rekursive Abfragen damit entschärft werden, da sie nun nur noch 1 mal pro Tag ausgeführt werden muss (1 Besucher muss sich also opfern, und die etwas längere Laufzeit in Kauf nehmen).
Ein weiterer Vorteil ist auch, dass der Server wesentlich entlastet wird, da er weniger Berechnungen durchführen muss und dadurch auch weniger Arbeitsspeicher für dieses Script verwenden muss.

Gibt es auch einen Nachteil von Caching?
Ja den gibt es leider auch: Während eine PHP-Datei, die nur die Daten heranholt, relativ wenig Webspace (= Festplattenspeicher) benötigt, muss mit Cashing zu jedem Ausgabeartikel eine HTML-Datei gespeichert werden. Das kann recht schnell sehr viel Platz einnehmen. Empfehlenswert ist ein eigener Server mit einer großen Festplatte. Auf Shared Hosting-Paketen ist Caching nicht zu empfehlen.

Trotzdem ist Caching eine tolle Möglichkeit die Performance von Anwendungen zu erhöhen.
Die Quellcodes für das Beispiel und die Benchmarks gibts wie immer zum Download.

UPDATE: Mir ist gerade noch eine Lösung für das Problem des hohen SPeicherplatzbedarfs eingefallen. Leider kostet das wieder recht viel der durch das Caching gewonnenen Performance: Man könnte die HTML-Ausgabedateien per gzip packen und somit per PHP recht leicht verarbeiten. Allerdings beträgt der Geschwindigkeitsvorteil vor der „normalen“ Ausgabe dann nur noch 2 % – dafür lohnt sich der Aufwand glaube nicht. Also entweder große Platte und richtiges Caching oder kleine Platte (bzw wenig Webspace) und kein Caching.

Jan hat 152 Beiträge geschrieben

35 Kommentare zu “Ausgaben in Cache speichern

  1. Hallo

    Mit Interesse verfolge ich seit kurzem deine Benchmarks, da ich derzeit an PHP Projekten arbeite, welche sehr effizient arbeiten sollen. Ich habe mir dafür eine eigene PHP Benchmark Umgebung geschrieben. (http://www.ilimitado.de/blog/programmierung/php/php-benchmark-environment-tool/)

    Vielleicht kann dieses Tool dir auch weiterhelfen, kannst es dir ja mal runterladen und testen. Deine PHP Fragmente wären dort einfach reinzuladen und zu benchmarken.

    gruß
    Daniel von ilimitado

  2. admin sagt:

    @Daniel: Interessantes Script, hat auf jeden Fall eine hübsche grafische Auswertung. Allerdings möchte ich PHP nicht mit PHP benchmarken, da ja der Benchmark auch geladen und interpretiert werden muss. Ich verwende lieber das Apache Benchmark Tool und ein Shell Script zum einfacheren Laden der Scripte. Dann hat man garantiert keinen Overhead.
    Die Ergebnisse sind da glaube ich genauer, aber trotzdem Daumen hoch für deine Umgebung !!!

  3. Tim sagt:

    Ich empfehle file_get_contents, um aus (kleinen!) Dateien zu lesen. file_get_contents ist seit PHP 5 verfügbar. Zum Speichern von Inhalten würde ich file_put_contents verwenden. Ich habe mehrere Tage damit verbracht, Inhalte aus Schleifen mit fopen() schnell zu cachen und auszulesen, da ich meine MySQLi Klasse zu langsam ist, 1.000.000 Einträge auszulesen und zu verarbeiten. Die erste Version der Caching Klasse hat wie folgt funktioniert: Jeder Durchlauf der Schleife hat eine eigene ID und wird in einer eigenen Zeile in der Datei gespeichert. Nach mehreren Tests hat sich die Verbindung aus serialize() mit base64_encode() am Schnellsten zum Speichern erwiesen. Das Auslesen wurde über eine Schleife gesteuert, die alles bis zum Ende der ID ausgelesen hat (Der Aufbau einer Zeile war „ID|content“). Ist die ID gleich der gesuchten ID, wird alles nach dem „|“ ausgelese (also der Inhalt). Dies musste nur noch mit base64 dekodiert und unserialized werden. Problem diser Methode war, dass sie sehr langsam ist. Meine zweite Idee war etwas komplizierter: Ich habe mir gedacht, dass die gecachte Schleife komplett und immer in der gleichen Reihenfolge ausgelesen wird. Warum durchsucht man bei jedem Item die Datei erneut nach der ID, obwohl die Zeile einfach die nächste ist? Dann habe ich die Klasse soweit umgeschrieben, dass bei der letzten ausgelesenen Zeile fortgesetzt wird. Es werden also alle Zeile bis zur letzten beginnend ab der letzten Zeile durchsucht. Was ist aber mit dem Anfang (0..letzte Zeile)? Nachdem PHP beim Ende der Datei angekommen ist und noch nichts gefunden hat, wird am anfang weitergesucht, bis die letzte Zeile erreicht worden ist. Diese Methode war im Vergleich zur ersten Version sehr viel schneller. Allerdings war die Caching Klasse immernoch langsamer, als wenn man sie weggelassen hätte. Eine Idee wäre noch gewesen, die IDs und Positionen der Datei in einen Array zu speichern. Bei 1 Mio. Einträgen muss die Datei erst komplett durchlaufen werden. Von daher habe ich mir nicht die Mühe gemacht, diese Methode zu testen. Zufällig habe ich einer PHP Befehlsreferenz irgendetwas von SQLite gelesen. Mir kam die Idee, einfach anstatt fopen() eine andere Datenbank zu verwenden. Das habe ich auch gemacht (ich verwende SQLite). Die Ergebnisse sind so gut, dass ich diese Methode direkt in die MySQLi Klasse eingebaut habe. Allerdings Bedarf die Implementierung noch etwas Überarbeitung, da es an Zeit fehlte das Caching sauber zu implementieren.

    Gruß
    Tim

  4. Robert sagt:

    Danke für diese einfache und dennoch im Ergebnis sehr zielführende Einleitung.
    Aufgrund vieler Datenbankanfragen und zugleich deutlich steigenden Benutzerzahlen werden die Ladezeiten meiner Seite (aus meiner Sicht) zu lang – was läge da näher als ein einfaches Caching. Dank Deiner Seite sind mir nun Funktionsweise sowie Minimalanforderungen inkl. Umsetzungsnippets klar. Und das in weniger als 5 Minuten: optiamle (lokale) Testvoraussetzungen. Danke.

  5. Moritz sagt:

    Das Skript ist eigentlich nicht schlecht. Großes kompliment von miner Seite aus. Wie Robert schon schrieb, ein Caching in 5min. Genial!!!

    Nur, wie sieht es aus wenn man z.B. ein Fotoalbum cachen möchte. Die Bilder werden dann trotzdem neu geladen, da nur die Ausgabe (HTML-Code) gespeichert wird, oder?

  6. Jan sagt:

    Die Bilder (wenn sie wirklich physisch vorliegen und nicht von PHP generiert werden), werden ja eh schon gecacht im Browser, ohne dass man sich drum kümmern muss.

    Wenn Du sie vorher per PHP bearbeitest, dann könntest Du über die HTTP-Header den Cache steuern. Wie das geht, habe ich bspw. hier beschrieben.

  7. Ingo Busch sagt:

    Hallo, nettes Script. Bin hier angekommen weil ich nach „gzip“ gesucht hatte genau in dem Zusammenhang. Ich finde das speichern als gzip sehr sinnvoll, die Rechenzeit kann man wie ich finde vernachlässigen. Wenn man sein Cache-Script ohnehin so um- oder ausbaut dass die Daten auch komprimiert an den Browser gesendet werden (bei mir gut 80%) dann kann man sie auch gleich so speichern. Das dürfte sogar noch schneller sein als zuvor, da die Daten dann schon komprimiert aus dem Cache kommen und nicht erst komprimier werden müssen. Ausnahme sind dann bei mir die knapp 20%, aber bisher waren es ja gut 80%.

  8. Christian sagt:

    Das ist ein klasse Tutorial zu Thema Caching. Wahrscheinlich werde ich aber stattdessen für mein nächstes Projekt einfach Dateien generieren, die nahezu statisch sind; lediglich der Logger wird dynamisch sein. Diese (nahezu) statischen Dateien generiere ich dann mittels eines PHP-Skripts in meinem Admin-Bereich. Das passt deshalb, weil sich die Dateie äußerst selten ändern sollten und wenn Änderungen vorgenommen werden, dann tue ich das sowieso über die Admin-Oberfläche.

  9. Gerhard sagt:

    Ich hatte vor kurzem ein PHP-Script, welches einen RSS-Feet von einer langsamen Seite holte und in den Inhalt der eigenen Seite integrierte. Der Einbau eines ähnlichen Filecaches (stündlich aktualisiert) brachte eine Verringerung der Ladezeit um 16 Sekunden auf 2 Sekunden und Trafficeinsparung 🙂

  10. Malocher sagt:

    Hallo,

    man könnte das ganze ja auch in die Datenbank schreiben, wäre das dann auch noch schneller?

    Gruß
    Malocher

  11. Jan sagt:

    @Malocher: Damit würdest Du das Problem des großen Datenbedarfs ja nur verlagern aber nicht lösen. Letztlich braucht der HTML-Code in der DB ja sogar noch mehr Speicherplatz als auf dem Dateisystem. Zumal man sich dann wieder Gedanken über eine performante Indexierung machen müsste, während das auf dem Dateisystem nicht nötig ist, weil man die Datei anhand des Dateinamens ruckzuck findet.

  12. Malocher sagt:

    Wäre es noch ein wenig schneller wenn man absolute Pfade zu den Dateien, und beim erzeugen file_put_contents() verwenden würde?

  13. Tim sagt:

    Danke für den Artikel. Dank ihm nutze ich bei meiner Seite ein ähnliches System. Nur das ich die im Artikel angesprochene Komprimierung nutze.

    [[code]]czo1Mjg6XCINCmlmKGZpbGVfZXhpc3RzKEFCU09MVVQgLiBcXFwnbnVyRWluQmVpc3BpZWwuaHRtbFxcXCcpKSB7DQoNCglpZihCcm93c2Vye1smKiZdfSBrYW5uIGd6aXApew0KCQkkbGVuZ3RoID0gZmlsZXNpemUoQUJTT0xVVCAuIFxcXCdudXJFaW5CZWlzcGllbC5odG1sLmd6XFxcJyk7DQoJe1smKiZdfQloZWFkZXIoXFxcJ0NvbnRlbnQtRW5jb2Rpbmc6IGd6aXBcXFwnKTsNCgkJaGVhZGVyKFxcXCdDb250ZW50LUxlbmd0aDogXFxcJy4kbGVuZ3RoKXtbJiomXX07DQoJCWhlYWRlcihcXFwnQ2FjaGUtQ29udHJvbDogbWF4LWFnZT03MjAwMFxcXCcpOw0KCQllY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKEFCU3tbJiomXX1PTFVUIC4gXFxcJ251ckVpbkJlaXNwaWVsLmh0bWwuZ3pcXFwnKTsNCgkJZXhpdCgpOw0KCQkNCgkvLyBFbmQgaWYNCgl9ZWxzZXsNCgkJL3tbJiomXX0vIEhlYWRlciBldGMuIC4uLg0KCQllY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKFxcXCdjb21wcmVzcy56bGliOi8vXFxcJyAuIEFCU09MVVQgLntbJiomXX0gXFxcJ251ckVpbkJlaXNwaWVsLmh0bWwuZ3pcXFwnKTsNCgkJZXhpdCgpOw0KCQ0KCS8vIEVuZCBlbHNlDQoJfQ0KDQovLyBFbmQgaWYNCntbJiomXX19DQpcIjt7WyYqJl19[[/code]]
    

  14. Tim sagt:
    if(file_exists(ABSOLUT . 'nurEinBeispiel.html')) {
    
    	if(Browser kann gzip){
    		$length = filesize(ABSOLUT . 'nurEinBeispiel.html.gz');
    		header('Content-Encoding: gzip');
    		header('Content-Length: '.$length);
    		header('Cache-Control: max-age=72000');
    		echo file_get_contents(ABSOLUT . 'nurEinBeispiel.html.gz');
    		exit();
    		
    	// End if
    	}else{
    		// Header etc. ...
    		echo file_get_contents('compress.zlib://' . ABSOLUT . 'nurEinBeispiel.html.gz');
    		exit();
    	
    	// End else
    	}
    
    // End if
    }
  15. Paul sagt:

    Hallo,

    kann man das oben genannte Beispiel auch nutzen wenn man direkt auf „nurEinBeispiel.html.gz“ verlinkt?

    Man müsste dann ja in der .htaccess prüfen ob der Browser Kompression versteht, und wenn ja, dann schickt man mit passendem Header einfach die komprimierte Datei los, und wenn nicht, dann muss man an ein PHP-Skript weiterleiten und die Datei als normales HTML erzeugen lassen.

    Ist das möglich?

  16. Xian sagt:

    @Paul:
    Das ist durchaus möglich. Du müsstest dann natürlich den richtigen Header (Header append Content-Encoding „gzip“) senden und per „AddType“ den Typ auf text/html setzen.

    Ich benutze dieses Cachen für meine RSS-Feeds (eine Stunde zwischenspeichern), da dort tendenziell der „regelmäßigste“ Traffic auftritt. Allerdings ohne Komprimierung… bei so wenigen, kleinen Dateien lohnt sich das nicht wirklich.

  17. Max sagt:

    Hallo,
    der Artikel ist zwar schon älter, aber da ja hier immernoch alles aktiv ist, will ich trotzdem mal schreiben.

    Wie sieht es denn aus wenn ich auf meiner Seite ein Login habe. Ich kann ja nun schlecht die Seite cachen lassen, auf der dann das Benutzermenü eines eingeloggten Benutzers erscheint. Kann ich bestimmte Teile vom Cache ausschließen? Wenn ja, wie?

  18. Alex sagt:

    Sehr interessanter Artikel. Doch eins Murkst es mir doch ein wenig: Ich kann es nicht leiden, wenn PHP -mehr oder weniger- unkontrolliert auf meinem Webspace schreibt;- am Ende muss man darauf schreiben können – un das im Internet *brr*
    Also war meine Idee: Kann man die Daten statt in Dateien in der Datenbank speichern, und so die SQl Abfragen auf 1 reduzieren? Gibt es in die Richtung schon ein Test?

  19. Ingo sagt:

    Klar geht das, ist aber nicht Sinn davon. So hast Du ja wieder eine DB Abfrage um den Cache zu laden und so gesehen ist das dann auch nichts anderes, denn die DB schreibt ja auch auf die Festplatte. Wo soll da also der Vorteil sein?

  20. Alex sagt:

    Als erstes wohl, dass PHP keine Datei anlegt und diese u.U. von Aussen lesbar/schreibbar ist. (chmod 777 z.B. bei Servern, wo der Eigentümer der Apache ist)

    Ich denke dabei an eine Webseite, die hunderte von Querys pro Seite hat – jeder Menüpunkt, jeder Grafik etc (Soll es ja geben in Zeiten von schlechter Modul-Programmierung und höllischer Plugin-Tipperei)

    Nun ist 1 eine Abfrage, mit ordentlichem „Where“ zu mindest schneller, als viele, viele andere hingewurschtelte Abfragen.

  21. Ingo sagt:

    Na also wenn es Dir nur um die Schreibrechte geht, dann passe das doch einfach entsprechend an. Wenn einer von außen schreiben will, dann muss er ohnehin Zugang haben. Nur weil die auf 777 steht heißt das ja noch lange nicht, dass da jeder Fremde schreiben darf wie er lustig ist. Ansonsten setzt eine htaccess mit Passwortschutz rein, dann ist die von außen gar nicht erreichbar. Serverintern wird die ignoriert.

  22. Alex sagt:

    Mir gehts primär um den Schreibschutz 😉

    Sekundär auch darum, dass es für mich logischer ist das eine (localhost-)mysql-Datenbank schneller ist als das lesen einer Datei – vorallem in der Hinsicht, dass die Datei immer und immer wieder gelesen wird und mysql das Ergebnis der Anfrage einfach Zwischenspeichern kann

  23. Ingo sagt:

    Hm, sorry, aber findest Du nicht, dass die Aussage nun etwas unlogisch ist? Was macht denn Mysql? Es bekommt eine Anfrage, sucht auf der Festplatte und liefert aus, wenn vorhanden. Beim Schreiben ist es das gleiche. Wieder ist es die Festplatte die die Daten hat, auch wenn es im MySQL-File ist. Du musst so oder so auf die Platte zugreifen. Warum sollte dann ein lokaler zugriff über mysql auf die Platte schneller sein als ein Zugriff der direkt auf die Platte geht? Und wenn es Dir nun um das Zwischenspeichern geht, damit der Cache nicht immer abgerufen wird, dann bringt da Mysql auch nicht viel, denn es werden nur die Query im qCache gespeichert. Für so etwas gibt es entsprechende Header die man senden kann oder eben direkt das entsprechende Modul vom Apache. Aber nicht falsch verstehen, mit der DB geht das schon, nur ist es halt unsinnig.

    Und der Schreibschutz. Wer soll denn schreiben können? Das kann so schon mal keiner. Mit einem Passwortschutz erst recht nicht und wenn der Cache unterhalb des Root liegt schon gleich drei mal nicht. Wo soll da denn das Problem sein? Vielleicht stehe ich ja auf dem Schlauch und habe Sicherheitslücken von denen ich nichts weiß 😉

  24. Thomas W sagt:

    @Ingo: „Warum sollte dann ein lokaler zugriff über mysql auf die Platte schneller sein als ein Zugriff der direkt auf die Platte geht?“

    1. MySQL hat intelligentere Caching-Algorithmen, und der Zugriff (insbesondere bei großen Datenmengen) ist bei MySQL einfach besser gelöst. So spare ich bei einem meiner Kunden immens Zeit dadurch, dass ich das Caching in einer MySQL-Tabelle auslagere. Diese Tabelle wird am Tag mehrere GB groß und enthält mehrere tausend Datensätze. Der Zugriff bleibt schnell. Noch effizienter wäre es, wenn man memcached im RAM nutzen würde. Ich hatte diese Daten mal auf der Festplatte, aber der I/O wurde dadurch gigantisch 🙂

    2. Bei Nutzung von mehreren Webfrontends benötigst du optimalerweise einen zentralen Cache-Storage. Wenn der dann auf nem iSCSI oder ähnlichem liegt, erzeugt dies immens I/O und das kostet wirklich Power. Hier ist MySQL intelligenter…

    Tip: Einfach eine MySQL-Tabelle schaffen, die mit nem Key angesprochen wird, und die Daten serialisiert bis zu einem gewissen Zeitpunkt vorhält. Für mich die beste Lösung, da hier bestimmte Teile eines Caches gelöscht werden können (durch DELETE FROM cachetable WHERE cachekey LIKE „blah%“) – was mit memcached so leider nicht funktioniert.

  25. Ingo sagt:

    @Thomas
    Mit Deinen Ausführungen hast Du soweit natürlich recht, aber das widerlegt doch nicht das von mir geschriebene, oder? MySQL kann so gut Cachen wie es mag, letztendlich müssen die Daten wieder auf die Platte, oder eben im RAM bleiben.

    Ich hatte meine Daten in der Datenbank und nun auf der Platte. Das sind auch gut 1,3 GB bei durchschnittlich 25kB pro File (kannst also die Anzahl erahnen). In der DB waren es durch den Index noch mal ca. 0,4 GB mehr, obwohl es damals wenig Daten waren.

    Daher kann ich auch das mit Deinem I/O nicht wirklich verstehen. Das hast Du überall und immer wenn Du nicht direkt im RAM arbeitest.

    Das Löschen in der DB ist einfacher, das stimmt. Geht so im Filesystem nicht direkt, aber das übernimmt mein Backend, damit habe ich gar nichts zu tun.

    Und was soll denn das Serialisieren bringen? Verstehe ich nun nicht. Was das ist schon, klar, aber bei HTML-Daten – was soll das denn nutzen? Ich speichere meine Daten gleich komprimiert, dann spare ich mir das gzip bei jeder Auslieferung, zumal die Auslieferung ja auch nur erfolgt, wenn sich die Daten geändert haben. Header 304 / eTag etc.

  26. Thomas W sagt:

    @ingo: Nein, das widerlegt es nicht. Aber: „…oder eben im RAM bleiben…“ – exakt, RAM ist schneller als Platte und kostet keinen I/O, MySQL cached diese Elemente im RAM soweit wie möglich, ohne dass man dies selbst beeinflussen muss.

    Das mit dem serialisieren hab ich allgemein gemeint, also nicht nur ganze Seiten ablegen, sondern auch Arrays für ganz andere Zwecke von Caching… Vielleicht ging mein Vorschlag auch in eine ganz andere Richtung 😉

    So wie Du es beschreibst, macht es ja auch Minify: http://code.google.com/p/minify/

    Prinzipiell ist der Zugriff auf eine MySQL-Tabelle mit tausenden Einträgen schneller als in Verzeichnis mit tausenden Dateien. Das zusammen mit dem MySQL-Caching – darauf wollte ich nur hinaus. Ach ja, man kann ja auch binäre Daten über nen BLOB ablegen. 🙂

  27. SIthlord sagt:

    Hi,

    danke für das Tutial. Ist interessant mal zu sehen, wie man das ganze aufbauen würde.

    Dein Ausgangspunkt war, viele, sich selten ändernde php Scripte kompiliert abzuspeichern. Dafür ist das Speichern auf der Festplatte mit Sicherheit der sinnvollere Weg.

    Das Cachen ist aber auch interessant bei Skripten, die sehr oft abgefragt werden, bei denen aber eine sekundengenaue Aktualität nicht unbedingt erforderlich ist.

    Worauf ich hinaus will:
    In dem von mir skizzierten Fall wäre es weit schneller, die kompilierten html Dateien im Ram abzuspeichern.
    Die Festplatte ist weit langsamer und Ram recht günstig.
    Wenn man ein paar Dateien mit hohen Zugriffszahlen beispielsweise alle 10min kompilieren und im Ram abspeichern würde, wären alle Zugriffe in den nächsten 10min sehr schnell.

    Danke nochmal und schöne Grüße
    Sithlord

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>