Matthias Apsel: Caching von dynamisch erstellten aber dann statischen Seiten

Hallo alle,

ich lasse durch ein PHP-Script HTML-Dateien in Abhängigkeit bestimmter Parameter erzeugen. Dies ist mit einigen Abfragen an eine Datenbank verbunden, dauert also ein paar Zehntelchen. Für dieselben Parameterwerte ergibt sich aber immer dasselbe HTML-Dokument, also bräuchte man dieses nicht jedes mal neu erstellen zu lassen. Dazu habe ich bei Jörg einen vielversprechenden, gut dokumentierten und deshalb verständlichen Lösungsansatz gefunden, danke an dieser Stelle dafür.

Im alten SELFHTML-Archiv wurden die HTML-Seiten selbst gespeichert. Ist das dieselbe Vorgehensweise?

Funktioniert dies

/* Mag der User-Agent gezippte Daten? */
        if ( false===strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') ) {
            /* Falls nicht packen wir nämlich für Ihn aus: */
            exec('cat '.FTX_CACHE_FILE.'|gunzip');

(Zeile 4) unabhängig vom Server oder kann es da Schwierigkeiten geben? Wenn es sich um HTML-Ressourcen handelt, brauche ich mich doch eigentlich nicht darum zu kümmern, ob die Seite gezippt wird? Das handeln doch der anfragende UA und der Server miteinander aus?

Bis demnächst
Matthias

--
Signaturen sind bloed (Steel) und Markdown ist mächtig.
  1. Hallo Matthias,

    ich lasse durch ein PHP-Script HTML-Dateien in Abhängigkeit bestimmter Parameter erzeugen. Dies ist mit einigen Abfragen an eine Datenbank verbunden, dauert also ein paar Zehntelchen. Für dieselben Parameterwerte ergibt sich aber immer dasselbe HTML-Dokument, also bräuchte man dieses nicht jedes mal neu erstellen zu lassen.

    Solange du nicht ernsthaft an Last-Probleme stösst würde ich das Caching weglassen. „Premature optimization is the root of all evil.“

    Im alten SELFHTML-Archiv wurden die HTML-Seiten selbst gespeichert. Ist das dieselbe Vorgehensweise?

    Im wesentlichen ja.

    Funktioniert dies

    /* Mag der User-Agent gezippte Daten? */
            if ( false===strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') ) {
                /* Falls nicht packen wir nämlich für Ihn aus: */
                exec('cat '.FTX_CACHE_FILE.'|gunzip');
    

    (Zeile 4) unabhängig vom Server oder kann es da Schwierigkeiten geben?

    Das kann Schwierigkeiten geben, abhängig vom Userland (nicht überall ist gzip installiert) und dem Environment (die PATH-Variable ist nicht selten leer). Ersteres würde ich ignorieren weil eher unwahrscheinlich, zweiteres ist aber schon öfter der Fall, da würde ich mit absoluten Pfadangaben (/bin/gunzip und /bin/cat) arbeiten.

    Aber eigentlich will man das auch nicht über die Shell lösen (und schon gar nicht mit cat, gunzip --to-stdout existiert), sondern über PHP selber. Da extra eine Shell zu starten verschwendet einen grossen Teil der gewonnenen Performance wieder.

    Wenn es sich um HTML-Ressourcen handelt, brauche ich mich doch eigentlich nicht darum zu kümmern, ob die Seite gezippt wird? Das handeln doch der anfragende UA und der Server miteinander aus?

    Wenn es sich um reine HTML-Ressourcen handelt, kann es Sinn machen, die Dateien vorzukomprimieren, sowohl Apaches mod_deflate als auch nginx' gzip-Implementierung unterstützen das (um mal zwei der am häufigsten genutzten Webserver zu nennen). Aber das hängt davon ab, ob du viel Traffic erwartest oder nicht. Ich würde idR davon Abstand halten, die meisten Seiten brauchen das nicht und die doppelte Datenhaltung muss berücksichtigt werden und erhöht so die Komplexität.

    LG,
    CK

    1. Moin!

      Das kann Schwierigkeiten geben, abhängig vom Userland (nicht überall ist gzip installiert) und dem Environment (die PATH-Variable ist nicht selten leer). Ersteres würde ich ignorieren weil eher unwahrscheinlich, zweiteres ist aber schon öfter der Fall, da würde ich mit absoluten Pfadangaben (/bin/gunzip und /bin/cat) arbeiten.

      Hehe. Das ist ja mein Zeug.

      Also:

      • zlib hat bei nicht das erwünschte Ergebnis gebracht.
      • das die Seiten serverseitig entpackt werden müssen ist SEHR selten, denn die SEHR weit überwiegende Zahl der Clients akzeptiert mit gzip gepackte Inhalte.

      Wenn es sich um HTML-Ressourcen handelt, brauche ich mich doch eigentlich nicht darum zu kümmern, ob die Seite gezippt wird? Das handeln doch der anfragende UA und der Server miteinander aus?

      Dann packt der Server diese erst beim Abruf, was Last verursacht. Hier sind diese bereits gepackt gespeichert.

      Ich würde idR davon Abstand halten, die meisten Seiten brauchen das nicht und die doppelte Datenhaltung muss berücksichtigt werden und erhöht so die Komplexität.

      Einfacher Trick: Die Daten werden bei ersten Abruf gepackt und bei Veränderung im CMS gelöscht. Deshalb ja auch "Cache".

      Der Abruf beweist übrigens, dass es prima funktioniert …

      Jörg Reinholz

      1. Hallo Jörg,

        • zlib hat bei nicht das erwünschte Ergebnis gebracht.

        Dann hast du etwas falsch gemacht :) denn gzip verwendet die libz.

        Ich würde idR davon Abstand halten, die meisten Seiten brauchen das nicht und die doppelte Datenhaltung muss berücksichtigt werden und erhöht so die Komplexität.

        Einfacher Trick: Die Daten werden bei ersten Abruf gepackt und bei Veränderung im CMS gelöscht. Deshalb ja auch "Cache".

        Daran ist nichts einfach. „There are only two hard things in Computer Science: cache invalidation and naming things.“

        Klar kann man das implementieren, das habe ich nicht bestritten, aber es fügt eine nicht unerhebliche Schicht Komplexität und damit jede Menge Fehlerquellen hinzu, die komplett vermieden werden können. Es reicht diese Optimierung einzubauen wenn man sie auch wirklich benötigt.

        LG,
        CK

        1. Moin!

          Hallo Jörg,

          • zlib hat bei nicht das erwünschte Ergebnis gebracht.

          Dann hast du etwas falsch gemacht :)

          Das vermute ich auch. Ich habe aber die Versuche im Hinblick darauf, dass das Auspacken sehr selten stattfindet, schnell abgebrochen, denn ich wollte fertig werden.

          Einfacher Trick: Die Daten werden bei ersten Abruf gepackt und bei Veränderung im CMS gelöscht. Deshalb ja auch "Cache".

          Daran ist nichts einfach. „There are only two hard things in Computer Science: cache invalidation and naming things.“

          Ich fand nicht, dass es ein Problem darstellt, denn ich habe eine ziemlich einfache und funktionierende(!) Lösung gefunden. Perfekt ist sie nicht, weil sie einfach ein wenig Performance liegen lässt. So lösche ich bei jeder Änderung im CMS einfach den kompletten Cache und es interessiert mich "nicht die Bohne", dass dieser dann erst nach und nach neu erstellt wird. Name? Einfach alles in den md5-Mixer. Reicht hier völlig aus.

          Es reicht diese Optimierung einzubauen wenn man sie auch wirklich benötigt.

          Es gibt Leute, die mich abgrundtief hassen - und jede einzelne dieser Personen ist kriminell. Ergo gab es DDoS-Attacken. Die letzte ging glatt durch: Denn auf jede Abfrage gab es brav die gewünschte Webseite. Ohne die Optimierung hätte das nicht geklappt. Manchmal sind halt hundertstel Sekunden entscheidend.

          Jörg Reinholz

          1. Hallo Jörg,

            tut mir leid, ich wusste nicht, dass es bei Matthias Frage um dein konkretes Problem geht. Ich hatte dir nicht unterstellen wollen, dass deine Lösung für dein konkretes Problem falsch ist.

            Ich wollte Matthias einen allgemeinen Ratschlag geben, denn mehr ist auf seine Fragestellung nicht möglich.

            LG,
            CK

            1. Moin!

              tut mir leid, …

              Das muss es nicht, denn

              1. ich war jetzt keine Sekunde sauer und weil
              2. im Hinblick auf alle denkbaren Umstände Die von Dir gegebenen Tipps ja goldrichtig sind, und weil Du anders als ich
              3. nicht auf den ersten Blick sehen konntest, was das für Zeug ist und in welchem Kontext das steht.

              Jörg Reinholz

            2. Hallo Christian Kruse,

              Hallo Jörg,

              tut mir leid, ich wusste nicht, dass es bei Matthias Frage um dein konkretes Problem geht. Ich hatte dir nicht unterstellen wollen, dass deine Lösung für dein konkretes Problem falsch ist.

              Es ging nicht um Jörgs konkretes Problem. Ich hatte überlegt, Jörgs Lösung zu verwenden.

              Ich wollte Matthias einen allgemeinen Ratschlag geben, denn mehr ist auf seine Fragestellung nicht möglich.

              Ja, sie ist recht allgemein gehalten. Ich glaube nicht, dass ich an Lastprobleme stoßen werde. Wenn hier niemand anderes behauptet, dass das, was du mir geantwortet hast, Blödsinn ist, werde ich deinen Rat beherzigen und die Seiten jedesmal neu erstellen lassen.

              Bis demnächst
              Matthias

              --
              Signaturen sind bloed (Steel) und Markdown ist mächtig.
              1. Moin!

                Wenn hier niemand anderes behauptet, dass das, was du mir geantwortet hast, Blödsinn ist, werde ich deinen Rat beherzigen und die Seiten jedesmal neu erstellen lassen.

                Hehe. Das kommt auf Umstände an, die uns unbekannt sind. Es kann ein "irrer Fehler" sein, nicht zu cachen und es kann genau so grundfalsch sein, das zu tun. Das betrifft dann auch die Frage, ob es schlau ist, dass auf die von mir gezeigte Weise zu tun.

                Zu den Lastproblemen gibt es einen letzten Absatz.

                Jörg Reinholz

                1. Hallo Jörg Reinholz,

                  Zu den Lastproblemen gibt es einen letzten Absatz.

                  Ja, ich hatte erst kürzlich im Forum davon gelesen und fand die Idee eigentlich gut.

                  Hehe. Das kommt auf Umstände an, die uns unbekannt sind. Es kann ein "irrer Fehler" sein, nicht zu cachen und es kann genau so grundfalsch sein, das zu tun. Das betrifft dann auch die Frage, ob es schlau ist, dass auf die von mir gezeigte Weise zu tun.

                  So. Dann wollen wir doch mal schauen, ob ich ein paar Umstände beitragen kann.

                  • die Parameter werden per mode_rewrite an das Script gegeben
                  • die Parameter stecken dabei sowohl in der query sondern im pfad der url
                  • wenn das Muster nicht passt, gibts einen 404
                  • wenn die Parameter ungültig sind, gibt es eine default-Seite
                  • zu sehen unter http://brückentage.info
                  • die Seitenzugriffe sind sehr unterschiedlich auf das Jahr verteilt, auf das Script erwarte ich weniger als 100 Zugriffe täglich
                  • der Server gehört mir nicht

                  Es geht dabei um die Ferienkalender, derzeit baue ich die noch Jahr für Jahr händisch, was natürlich sehr umständlich ist, aber keine Datenbank benötigt. Das im OP erwähnte Script soll mir diese Arbeit abnehmen.

                  Die Frage ist, ob ich mir die letztlich 25 Dateien pro Jahr als includes ablege oder jedes mal neu erstelle.

                  Bis demnächst
                  Matthias

                  --
                  Signaturen sind bloed (Steel) und Markdown ist mächtig.
                  1. Moin!

                    Hallo Jörg Reinholz,

                    Zu den Lastproblemen gibt es einen letzten Absatz.

                    Ja, ich hatte erst kürzlich im Forum davon gelesen und fand die Idee eigentlich gut.

                    Hehe. Das kommt auf Umstände an, die uns unbekannt sind. Es kann ein "irrer Fehler" sein, nicht zu cachen und es kann genau so grundfalsch sein, das zu tun. Das betrifft dann auch die Frage, ob es schlau ist, dass auf die von mir gezeigte Weise zu tun.

                    So. Dann wollen wir doch mal schauen, ob ich ein paar Umstände beitragen kann.

                    • die Parameter werden per mode_rewrite an das Script gegeben
                    • die Parameter stecken dabei sowohl in der query sondern im pfad der url
                    • wenn das Muster nicht passt, gibts einen 404
                    • wenn die Parameter ungültig sind, gibt es eine default-Seite

                    Wenn überhaupt packen, dann ab hier. Schalte alles außer Get-Parameter ab.

                    • zu sehen unter http://brückentage.info
                    • die Seitenzugriffe sind sehr unterschiedlich auf das Jahr verteilt, auf das Script erwarte ich weniger als 100 Zugriffe täglich

                    Aja. Da stellt sich die Frage nach dem Aufwand.

                    • der Server gehört mir nicht

                    Irrelevant, würde aber genau genommen sogar für das Packen sprechen. Auf einem eigenen Server kann man radikaler auf DDoS-Attacken reagieren als auf einem Shared Host. Zum Beispiel ganze A-Netze aus China rauswerfen.

                    Es geht dabei um die Ferienkalender, derzeit baue ich die noch Jahr für Jahr händisch, was natürlich sehr umständlich ist, aber keine Datenbank benötigt. Das im OP erwähnte Script soll mir diese Arbeit abnehmen.

                    Aja. Da hätte ich eine ganz andere Idee.

                    Die Frage ist, ob ich mir die letztlich 25 Dateien pro Jahr als includes ablege oder jedes mal neu erstelle.

                    Beides: Nö. Siehe oben (Feiertagsskript). Das bisschen Datumsrechnen und Array-Schieben geht sehr schnell und rechtfertigt den Aufwand nicht. Also: Skripte die Brückentage unter Berücksichtigung von Bundesland, speziellen "Katholen-Ecken" und Augsburg (8.8.)

                    Jörg Reinholz

                    1. Hallo Jörg Reinholz,

                      Es geht dabei um die Ferienkalender, derzeit baue ich die noch Jahr für Jahr händisch, was natürlich sehr umständlich ist, aber keine Datenbank benötigt. Das im OP erwähnte Script soll mir diese Arbeit abnehmen.

                      Aja. Da hätte ich eine ganz andere Idee.

                      Ferien, nicht Feiertage, aber letztere auch berechnen zu lassen, ist vielleicht gar nicht schlecht. Via mobile, nicht unhöflich gemeint.

                      Bis demnächst
                      Matthias

                      --
                      Signaturen sind bloed (Steel) und Markdown ist mächtig.
                      1. Moin!

                        Ferien

                        Ok. Die lassen sich, anders als die Brückentage, nicht berechnen. Allenfalls effektiv erfassen. Da ist tatsächlich eine statische HTML-Datei, die womöglich durch ein Skript erzeugt wird, "Cache genug".

                        Jörg Reinholz

                    2. Hallo,

                      Es geht dabei um die Ferienkalender, ...

                      Aja. Da hätte ich eine ganz andere Idee.

                      kann es sein, dass du gerade den Unterschied zwischen gesetzlichen Feiertagen und Schulferien übersiehst?

                      Feiertage kann man "berechnen", sofern sie nicht sowieso auf ein bestimmtes Datum festgelegt sind (Tag der Arbeit, Weihnachten). Schulferien sind dagegen vielfach an Feiertage gekoppelt (Oster- oder Pfingstferien), aber ebenso oft auch davon losgelöst (z.B. Sommer- und Herbstferien).

                      Solange die Ferientermine der einzelnen Bundesländer also keinem algorithmischen Schema folgen, sondern Jahr für Jahr individuell (AFAIK) von der KMK festgelegt werden, bleibt Matthias wohl nichts anderes übrig, als diese Termine in seinem Script ebenfalls händisch zu pflegen.

                      So long,
                       Martin

                      1. Hallo,

                        bleibt Matthias wohl nichts anderes übrig, als diese Termine in seinem Script ebenfalls händisch zu pflegen.

                        Oder eine Möglichkeit finden, sie aus den offiziellen Mitteilungen zu extrahieren.

                        Gruß
                        Kalk

                        1. Moin!

                          An sich kam der Martin ja etwas spät.

                          Oder eine Möglichkeit finden, sie aus den offiziellen Mitteilungen zu extrahieren.

                          Das würde ich nur anfassen, wenn die "offiziellen Mitteilungen" in einem standardisiertem Format erfolgen. Aber Google behauptet sogar, dass es das gäbe.

                          Jörg Reinholz