+ Antworten
Ergebnis 1 bis 9 von 9

Thema: [Tutorial] Caching - Dynamische Seiten beschleunigen

  1. #1
    TP-Specialist phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts phpBuddy ist einer der Eckpfeiler des TP - ohne ihn geht nichts Avatar von phpBuddy
    Registriert seit
    Aug 2004
    Ort
    Kaiserslautern
    Beiträge
    4.678

    [Tutorial] Caching - Dynamische Seiten beschleunigen

    Vorwort

    Webseiten mit PHP zu erstellen ist schon eine tolle Sache. Noch besser wird es, wenn man seine ganzen Daten und Informationen aus einer Datenbank ziehen kann. Ein paar Funktionen hier, eine Datenbankverbindung da, dazu noch einige Queries und schon wird die dynamisch generierte Seite zum Besucher geschickt. Möchten jetzt 500 Leute die selbe Seite gleichzeitig sehen ( z.B. eine Produktseite in einem Onlineshop ) werden die eben erwähnten Funktionen, Datenbankverbindung und Queries eben 500 mal ausgeführt - nur um eine identische Information 500 anzuzeigen!
    Was auf den ersten Blick so dynamisch wirkt, entpuppt sich schnell als eine statische Information die bei jedem Abruf wieder und wieder Ressourcen belegt und somit den Server belastet. Abhilfe kann hier das sogenannte Caching schaffen.

    In diesem Tutorial möchte ich eine recht simple Variante vorstellen, damit der Leser einen Einblick bekommt wie Caching funktioniert.



    Was ist Caching und wie funktioniert es?

    Als Caching bezeichnet man das zwischenspeichern von Informationen bzw Daten, damit diese bei einem erneuten Aufruf sofort zur Verfügung stehen. Anders ausgedrückt bedeutet das für uns und dieses Tutorial: Wir nehmen eine dynamisch generierte Seite und wandeln sie ( temporär ) in eine statische HTML-Seite um.
    Die Vorteile einer statischen Seite liegen auf der Hand:
    • Schnellerer Seitenaufbau, weil weniger Daten durch den Parser gejagd werden müssen. Statt die angeforderten Daten dynamisch zu generieren wird lediglich eine statische Seite eingebunden.
    • Der Server wird -teilweise massiv- entlastet, weil weniger Ressourcen belegt werden. Es müssen keine Variablen, Funktionen und Klassen im Arbeitsspeicher gehalten werden, die Kommunikation mit dem Datenbankserver entfällt. Somit können Aufrufe von mehr Besucher schneller bedient werden.
    • Teilweise lassen sich auch Ausfälle der Datenbank abfangen, da man Daten aus dem Cache anzeigen lässt statt sie aus der DB zu laden.
    Das liest sich ja recht gut, aber leider ist nicht alles Gold was glänzt. Zu den negativen Punkten komme ich im Fazit.



    Voraussetzungen

    Da dieses Tutorial ausschließlich das Caching zum Thema hat sollte der Leser folgendes mitbringen
    • einfache PHP Kenntnisse
    • Erfahrung im Umgang mit Datenbanken ( auslesen, updaten, einfügen, etc. )
    • Grundlagenwissen im Umgang mit Dateien ( schreiben, lesen, löschen )

    Da die Mehrheit sicherlich noch PHP 4.x.x einsetzt, werde ich mich in diesem Tutorial auch daran halten. Für PHP5 User werde ich aber auch kurz den bequemeren Weg zeigen. Die Unterschiede sind nicht wirklich gravierend, sondern ersparen einem mit PHP5 nur Schreibarbeit.


    Los geht's... Caching im Einsatz

    Schauen wir uns nun an wie das in der Praxis funktioniert. Die hier benutzen Datenbankzugriffe und Ausgaben sollten Basiswissen sein und werden hier nicht weiter erläutert. Als Anschauungsobjekt dient hier ein Gästebuch aus dem wir die ersten 3 Einträge auslesen möchten. Zugegeben, ein Gästebuch ist hier ein suboptimales Beispiel, aber es geht auch nur um das verdeutlichen der Caching-Technik.



    Das Script ohne Caching

    PHP-Code:
    <?php
    // Zur DB verbinden und Tabelle auswaehlen
    $conid = @mysql_connect"localhost""root""" ) or die( "Fehler: MySQL nicht erreichbar!" );
    mysql_select_db"gaestebuch"$conid );

    // Daten aus der DB holen
    $result mysql_query"SELECT `nachricht` FROM `gaestebuch` LIMIT 3" );

    // Datensaetze ausgeben
    while ($zeile mysql_fetch_array$result ) )
    {
        echo 
    nl2brhtmlspecialchars$zeile['nachricht'] ) ). "<hr>";
    }

    // Ressourcen freigeben und DB-Verbindung schliessen
    mysql_free_result$result );
    mysql_close$conid );
    ?>
    Wie hier zu sehen ist, handelt es sich um ein ganz banales Script das sich zu einer Datenbank verbindet, 3 Einträge aus dem Gästebuch holt und diese dann in einer Schleife ausgibt. Danach werden artig die Ressourcen wieder freigegeben und alles ist bestens. Greifen jetzt aber unsere fiktive 500 Besucher gleichzeitig auf das Gästebuch zu, wird der oben stehen Code 500 Mal ausgeführt und belegt 500 Mal Ressourcen. Das geht doch bestimmt effektiver, oder?!



    Das Script mit anlegen der Cache Datei

    PHP-Code:
    <?php
    // Der interne Ausgabe-Puffer wird aktiviert
    ob_start();

    // Zur DB verbinden und Tabelle auswaehlen
    $conid = @mysql_connect"localhost""root""" ) or die( "Fehler: MySQL nicht erreichbar!" );
    mysql_select_db"gaestebuch"$conid );

    // Daten aus der DB holen
    $result mysql_query"SELECT `nachricht` FROM `gaestebuch` LIMIT 3" );

    // Datensaetze ausgeben
    while ($zeile mysql_fetch_array$result ) )
    {
        echo 
    nl2brhtmlspecialchars$zeile['nachricht'] ) ). "<hr>";
    }

    // Ressourcen freigeben und DB-Verbindung schliessen
    mysql_free_result$result );
    mysql_close$conid );

    // Die Daten vom Puffer werden umladen
    $output ob_get_contents();

    // Die Cache-Datei anlegen und die Daten hinein schreiben
    $datei fopen"cache/nachrichten.htm""w" );
    fwrite$datei$output );
    fclose$datei );

    // Puffer an den Browser ausgeben und die Pufferung deaktivieren
    ob_end_flush();
    ?>
    Im Vergleich zum vorherigen Listing wurden nur wenige Zeilen ergänzt, aber die haben es in sich!

    Gehen wir kurz die neuen Zeilen durch um zu sehen was dahinter steckt.

    PHP-Code:
    ob_start() 
    Damit wird der PHP-interne Ausgabepuffer eingeschaltet. Alles was ab jetzt als Ausgabe erscheinen würde ( in unserem Script die echo-Befehle in der while()-Schleife ) landet statt auf dem Bildschirm als String im Puffer. Sofern man nicht an einer bestimmten Stelle im Script die Daten im Puffer verarbeitet, wird am Ende des Scripts automatisch ein ob_end_flush() ausgelöst und die Daten werden an den Browser gesendet.

    PHP-Code:
    $output ob_get_contents(); 
    Mit ob_get_contents() werden die Daten aus dem internen Puffer an die Variable $output übergeben, wo sie auf eine weitere Verarbeitung warten.

    PHP-Code:
    $datei fopen"cache/gaestebuch.htm""w" );
    fwrite$datei$output );
    fclose$datei ); 
    Dieser Code sollte bekannt sein, da hier lediglich eine HTML-Datei im Ordner cache angelegt und der Inhalt von $output darin abgelegt wird.
    Hinweis: Der Ordner cache muß bereits existieren und Schreibrechte besitzen!

    PHP-Code:
    ob_end_flush(); 
    Diese Zeile sendet den Puffer an den Browser, damit dort nicht einfach eine weiße Seite angezeigt wird. Anschliessend wird die Pufferung beendet und der Arbeitsspeicher freigegeben.

    Na toll, jetzt erzeugen/überschreiben wir also jedesmal eine Datei wenn jemand die Seite aufruft. Irgendwie ist das aber noch nicht so das Gelbe vom Ei!?
    Was uns jetzt noch fehlt ist die Möglichkeit...:
    • zu prüfen ob beim Seitenaufruf bereits eine entsprechende Cache-Datei existiert. Falls Nein, wird eine erzeugt. Falls Ja, dann...
    • die Cache-Datei anzeigen lassen, statt erst eine dynamische Seite zu generieren.
    • festzustellen ob die Cache-Datei überhaupt noch aktuell ist oder ob es nicht bereits eine aktuellere Version geben sollte.



    Das fertige Script

    PHP-Code:
    <?php
    // Pfad und Name der Cache-Datei und Gueltigkeitsdauer in Sekunden
    $CacheDatei "cache/gaestebuch.htm";
    $CacheDauer 3600;

    // Pruefen ob eine entsprechende Cache-Datei bereits existiert
    // und ob sie noch gueltig ist
    if (file_exists$CacheDatei ) &&
       (
    time() - filemtime$CacheDatei )) < $CacheDauer )
    {
        
    // Statt die Seite dynamisch generieren zu lassen wird die
        // statische HTML-Datei eingebunden
        
    include( $CacheDatei );
        exit();
    }

    // Der interne Ausgabe-Puffer wird aktiviert
    ob_start();

    // Zur DB verbinden und Tabelle auswaehlen
    $conid = @mysql_connect"localhost""root""" ) or die( "Fehler: MySQL nicht erreichbar!" );
    mysql_select_db"gaestebuch"$conid );

    // Daten aus der DB holen
    $result mysql_query"SELECT `nachricht` FROM `gaestebuch` LIMIT 5" );

    // Datensaetze ausgeben
    while ($zeile mysql_fetch_array$result ) )
    {
        echo 
    nl2brhtmlspecialchars$zeile['nachricht'] ) ). "<hr>";
    }

    // Ressourcen freigeben und DB-Verbindung schliessen
    mysql_free_result$result );
    mysql_close$conid );

    // Die Daten im Puffer umladen
    $output ob_get_contents();

    // Die Cache-Datei anlegen und die Daten hinein schreiben
    $datei fopen$CacheDatei"w" );
    fwrite$datei$output );
    fclose$datei );

    // Puffer an den Browser ausgeben und die Pufferung deaktivieren
    ob_end_flush();
    ?>
    Hinzugekommen ist nur der obere Teil des Scripts. Zuerst setzen wir den Pfad und Namen zur Cache-Datei, dann noch die Zeit in Sekunden wie lange die Cache-Datei als gültig angesehen wird. Ist die Datei älter als erlaubt, wird beim nächsten Aufruf der Seite die Cache-Datei neu generiert.

    PHP-Code:
    if (file_exists$CacheDatei ) &&
       (
    time() - filemtime$CacheDatei )) < $CacheDauer )
    {
        
    // Statt die Seite dynamisch generieren zu lassen wird die
        // statische HTML-Datei eingebunden
        
    include( $CacheDatei );
        exit();

    In der IF-Anweisung wird geschaut ob die Cache-Datei existiert und ob sie noch gültig ist. Falls nicht, wird der Block übersprungen und eine neue Datei erzeugt. Falls aber alle Kriterien zutreffen, wird einfach nur die statische HTML-Datei eingebunden und das Script per exit(); verlassen. Wir sparen uns hier also die komplette DB-Kommunikation und das erneute anlegen der Cache-Datei. Somit wird nur einmal alle 3600 Sekunden ( 1 Stunde ) eine Seite generiert und an unsere 500 Besucher ausgegeben, statt 500 Mal die Datenbank zu kontaktieren um die Seite dynamisch erzeugen zu lassen!



    Das Script für PHP 5 User

    Mit PHP 5 kamen einige neue Funktionen hinzu, die einem Schreibarbeit abnehmen. Dieser PHP 4 Block...
    PHP-Code:
    // Die Daten im Puffer umladen
    $output ob_get_contents();

    // Die Cache-Datei anlegen und die Daten hinein schreiben
    $datei fopen$CacheDatei"w" );
    fwrite$datei$output );
    fclose$datei );

    // Puffer an den Browser ausgeben und die Pufferung deaktivieren
    ob_end_flush(); 
    ...läßt sich verkürzen indem man statt dessen...

    PHP-Code:
    file_put_contents$CacheDateiob_get_flush() ); 
    ...diesen Einzeiler verwendet.



    Das Fazit

    Wie man sieht läßt sich mit sehr wenigen Zeilen Code eine Verbesserung einbauen die auf stärker frequentierten Seiten doch zu erheblichem Geschwindigkeitszuwachs beitragen kann. Die Entlastung für den Server ist enorm und auch die Besucher bekommen schneller die angeforderte Information auf den Bildschirm.

    Bevor jetzt alle anfangen ihre Scripts umzuschreiben möchte ich noch kurz auf die eingangs erwähnten negativen Punkte dieses Verfahrens eingehen.
    Für kleine(re) Seiten lohnt sich der Aufwand kaum, da der Performancegewinn minimal ist. Für größere Projekte kann es sich sehr wohl lohnen aber man sollte bedenken, daß der zusätzlich benötigte Platz auf dem Server enorm sein kann. Immerhin müssen die Daten doppelt vorhanden sein, einmal in der DB, einmal als HTML-Variante. Es empfiehlt sich auch ein eigener Server, da das Dateisystem bei Shared Hosting i.d.R. unter einer recht hohen Belastung steht und der Performancegewinn durch lange Festplatten-Zugriffszeiten wieder zunichte gemacht wird. Letztendlich findet man das aber nur in einem praktischen Testlauf heraus.

    Das oben gezeigte Verfahren dient nur als Einblick. Effektiv wird es natürlich erst, wenn man ein Projekt von Grund auf mit Cache-System plant. Letztendlich bleibt es der Phantasie des User überlassen, auf welche Art so ein Cache-System eingebaut werden soll.

    Ich hoffe dieses kleine Tutorial ist dem ein oder anderen von Nutzen und wünsche ein erfolgreiches Caching

    Zum Abschluß gibt es noch die...



    Link-Übersicht

    Benutzte PHP-Funktionen

  2. #2
    TP-Member dichter macht alles soweit korrekt Avatar von dichter
    Registriert seit
    Feb 2005
    Beiträge
    74
    Das hört sich sehr ja nützlich an. :-)
    super erklärt, vielen dank!
    hi

  3. #3
    TP-Junior ronsn macht alles soweit korrekt
    Registriert seit
    Mar 2007
    Ort
    Berlin
    Beiträge
    17
    Danke für dieses Beispiel.
    Ich hab mir dazu auch Gedanken gemacht und möchte mal wissen, wie ihr darüber denkt.

    In deinem Beispiel regenerieren wir die Datei nach mindestens einer Stunde.
    Da sich dein Beispiel nur auf das Lesen von Contents bzw. die Ausgabe des Contents, aber nicht auf das Schreiben, bezieht ist es bei einem Gästebuch wohl nicht schlimm, wenn erst nach einer Stunde der Content neu geladen würde.
    Wenn ich mir jedoch ein Forum vorstelle, müssten die User eine Stunde warten, bis neue Beiträge angezeigt würden.
    Was kann man da nun machen? Die Zeit zwischen der Regenerierung verkürzen? Da stell ich mir wieder ein Forum vor. Die User warten trotzdem noch eine gewisse Zeit. Aber würden wir die Zeit zu niedrig einstellen, dann könnten wir ja gleich wieder auf die altbewährte Methode zurückgreifen.

    Mit dem Wissen, das Server sehr gut darin sind statische Dateien einfach wiederzugeben, würde ich ungerne auf das Cachen verzichten.
    Statistisch gesehen, greifen die Besucher einer Seite weniger schreibend, als lesend auf eine Seite zu, was noch ein Grund ist, die Dateien zu cachen.

    Daher habe ich mir überlegt, ob es nicht effektiver wäre, wenn man die Datei nur dann regeneriert, wenn neue Daten in der Datenbank liegen.
    Dazu kann man jedesmal, wenn ein neuer Eintrag getätigt wird eine Datei erzeugen, in welcher Informationen stehen, welche Daten dazugekommen sind bzw. geändert worden sind. Es soll also nur eine Informationsdatei erzeugt werden.
    Und hier kommt dein Beispiel wieder.
    Anstatt hier nach der Zeit zu gehen, können wir prüfen, ob eine Informationsdatei vorhanden ist. Wenn ja, dann lese diese aus und schaue, welche Daten aktualisiert wurden.
    In diesem Fall, wird eine Neue Cache-Datei angelegt und die Informationsdatei gelöscht.
    Wenn keine Informationsdatei vorhanden ist, wird die alte Cache-Datei ausgegeben.

    In wechler Art man eine Informationsdatei anlegt, oder ob man leere Informationsdateien mit verschiedenen Namen erzeugt, will noch erörtert werden. Immerhin habe ich gelesen, dass die Funktion is_file() sehr schnell sei, womit ich lieber ein System mit unterschiedlich nominierten Dateinamen bevorzugen würde.
    Geändert von ronsn (16.08.2007 um 16:55 Uhr) Grund: Qualitätssicherung

  4. #4
    TP-Senior Andy010 macht alles soweit korrekt Avatar von Andy010
    Registriert seit
    Mar 2003
    Ort
    Bamberg
    Beiträge
    126

    Cache-Datei löschen

    Hi,

    würde es nicht reichen die Cache-Datei einfach zu löschen bei neuem Eintrag? So könnte man auch die Cache-Dauer ganz weglassen!

    Gruß Andy
    Schönen Gruß aus Franken!

  5. #5
    TP-Veteran manuelito hilft, wo's geht manuelito hilft, wo's geht manuelito hilft, wo's geht Avatar von manuelito
    Registriert seit
    Sep 2002
    Beiträge
    1.229
    Jep, man muss das Cachefile einfach neu generieren, sobald ein Inhalt geändert wird. Das ist relativ einfach bei bei diesem Beispiel, bei komplexeren Inhalten wird es dann wieder schwierig, weil man die Zusammenhänge unter verschiedenen Inhalten kennen muss, die in eine cachbare Seite integriert werden. Ist aber alles machbar
    Wer sabotiert eigentlich ständig meine Signatur?

  6. #6
    TP-Special Mod steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User Avatar von steffenk
    Registriert seit
    Feb 2005
    Ort
    Haan / NRW
    Beiträge
    12.869
    Je komplexer das System wird (z.B. mit Forum, Gästebuch etc) sollte mans sich ein mehrschichtiges Cache bauen. So kann eine Seite aus verschiedenen Objekten bestehen:
    - cached static Data
    - noncached dynamic Data

    So kann man die Seite aus mehreren Teilen zusammensetzen. Ein Löschen der Cachedatei ist eine brutale Methode, die Seite muss komplett neu gerendert werden. Mit der Mehrschichtigkeit muss man nur die Teile neu generieren, die sich verändert haben.


    TYPO3 · MySQLDumper · dislabs
    ·
    manche Mühlen mahlen schneller ...
    "Ich habe Rücken"
    Horst Schlämmer


  7. #7
    TP-Senior Andy010 macht alles soweit korrekt Avatar von Andy010
    Registriert seit
    Mar 2003
    Ort
    Bamberg
    Beiträge
    126
    Und den dynamischen Teil könnte man bei der Änderung gleich rendern. Hört sich nicht mal so kompliziert an. Warum macht man das nicht von grundauf schon so?
    Für den Server dürfte es wohl auch keine größere Belastung sein.
    Schönen Gruß aus Franken!

  8. #8
    TP-Special Mod steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User steffenk lebt für das TP und seine User Avatar von steffenk
    Registriert seit
    Feb 2005
    Ort
    Haan / NRW
    Beiträge
    12.869
    ist auch nicht so kompliziert, das Konzept muss halt stimmen. Und das setzt vorraus, das man Objekte für die Seite definiert. Jedem Objekt gibt man die Eigenschaft für cached/noncached mit, ein PageGenerator geht das Array der Objekte durch und holt sich die aus dem Cache oder fordert das Rendern an.

    Für den Server ist das ganz klar eine Entlastung.


    TYPO3 · MySQLDumper · dislabs
    ·
    manche Mühlen mahlen schneller ...
    "Ich habe Rücken"
    Horst Schlämmer


  9. #9
    TP-Newbie Matzi macht alles soweit korrekt
    Registriert seit
    Jan 2010
    Beiträge
    4
    Hallo,

    klasse Erklärung. Für einem wie mich, mit noch wenig Kenntnissen, las es sich einfach und man konnte es auch umsetzen.
    Nun habe ich aber eine Frage dazu. Ich habe auf meiner Seite im Header ein Uhrezeitscript mit eingebaut. Dies wird nun auch gecacht. Ist es möglich, gewisse Scripte vom Cachen auszunehmen? Beim aufrufen der gecachten Zeiten beginnt die Zeit vom Punkt der Speicherung an zu laufen.
    Es wäre schön, wenn mir jemand Tipps dazu geben könnte.
    Vielen Dank

+ Antworten

Stichworte

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51