Ankündigung

Einklappen
Keine Ankündigung bisher.

3,32: Caching leichtgemacht

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • 3,32: Caching leichtgemacht

    3,32:
    In Zeiten des superschnellen Internets sind die Webentwickler mehr denn je gefordert ihre Webapplikationen möglichst performant zu erstellen. Zu Zeiten des 56k-Modems hat es noch niemanden wirklich interessiert, wie lange der Server braucht, um die Daten aufzubereiten, da es im Vergleich zur Datenübertragung eine verschwindend geringe Zeit war. Im Hier und Jetzt sieht das jedoch völlig anders aus: Die Serververarbeitungszeit kann schon mal die größte Zeitspanne im gesamten Ladevorgang darstellen.

    Eine wichtige und effektive Methode, um diese Zeit zu verringern, ist dabei das Cachen. Caching bedeutet nicht nur Geschwindigkeitszuwachs, sondern auch weniger Serverauslastung. Ein wünschenswertes Ergebnis also und die Methode ist keineswegs neu. Im Gegenteil: so ziemlich alle Internetsurfer benutzen einen Cache: den Browsercache. Wahrscheinlich wissen 95% der User nicht das sie ihn benutzen, aber er ist dennoch ein Feature was unglaubliche Ladezeit einspart. Der Browsercache ist aber nicht die einzige Art die den Webentwicklern zur Verfügung steht, er soll hier dennoch erläutert werden, zusammen mit seinen Verwandten.

    Cache Allgemein
    Ein Cache ist ein Speicher um Daten, die bereits einmal vorlagen, beim der nächsten Anfrage schneller zur Verfügung stellen zu können. Schneller zur Verfügung gestellt werden können diese Daten, indem der Cache ein schnelleres Speichermedium benutzt als die Originaldaten oder aber indem aufwendig generierte Daten überhaupt erst mal gespeichert werden, die sonst jedes Mal neu generiert werden müssten. Es gibt Caches sowohl im Hard- als auch im Softwarebereich.

    Browsercache
    Der Browsercache legt statische Dateien wie Bilder, CSS- und JS-Files auf dem Client-Rechner ab. Das hat zur Folge, dass bei einer erneuten Anfrage des Browsers diese Dateien nicht erneut aufwendig über das Netzwerk transferiert werden müssen, sondern schnell von der Festplatte des Benutzers geholt werden können. Generell können alle Dateien gecached werden, es macht jedoch bei dynamischen Dateien häufig keinen Sinn. Ob Dateien aus dem Cache geholt werden oder nicht, entscheidet der Browser anhand der vom Webserver gelieferten Header. Hier werden zum Beispiel das Änderungsdatum und die Größe der Datei übermittelt und dadurch weiß der Browser, ob sich die Datei auf dem Server verändert hat oder ob diese den gleichen Inhalt wie die auf der Festplatte hat. Über diese Header des HTTP-Requests lässt sich somit auch das Cache-Verhalten des Browsers über PHP und/oder den Webserver steuern.

    Datenbankcache
    Die meisten Datenbanksysteme haben auch einen eigenen internen Cache. Dort werden Ergebnisse von Abfragen zwischengespeichert um bei einer erneuten Anfrage die Daten schneller bereit stellen zu können. Das klappt deswegen, weil die Ergebnisse im Arbeitsspeicher des Servers gehalten werden und der Arbeitsspeicher ist ein wesentlich schnelleres Medium als die Festplatte. Außerdem werden die Daten bereits aufbereitet gelagert, somit entfallen einige interne Schritte der Datenbank, die sonst Zeit kosten. Einige Datenbankabfragen können wegen der unglücklichen Formulierung nicht gecached werden, deshalb sollte man sowas im Hinterkopf behalten:

    Nicht-cachebar:
    Code:
    SELECT * FROM tabelle WHERE datum = DATE_FORMAT(NOW(),’%y-%d-%m’)
    Cachebar:
    Code:
    SELECT * FROM tabelle WHERE datum = ‘2010-12-10’
    Die beiden Queries liefern dasselbe Ergebnis, daher sollte man hier also bspw. mit PHP das aktuelle Datum in das Query einfügen, da die Datenbank nicht davon ausgehen kann das interne Funktionen immer das gleiche Ergebnis liefern. Der Cache der Datenbank ist weitestgehend unsichtbar, lässt sich aber dennoch über Servereinstellungen konfigurieren und über bestimmte Queries auch etwas steuern.

    PHP Cache-Erweiterungen
    PHP Erweiterungen wie APC (Alternative PHP Cache) organisieren das cachen des PHP-Codes selber. Ist der Code einmal interpretiert worden, so muss sich der PHP Interpreter nicht erneut darum kümmern, sondern es kann direkt aus dem Shared-Memory des Webservers aufgerufen werden. Es gibt unterschiedliche Cache-Erweiterungen die unterschiedlich arbeiten, die meisten bieten jedoch den Entwicklern die Möglichkeit Daten dort abzulegen und beim nächsten Zugriff diese Daten direkt aus dem Arbeitsspeicher statt aus einer langsameren externen Quelle zu holen.

    Eigenen Cache nutzen
    Bei Webapplikationen wie CMS Systemen kann es durchaus Geschwindigkeit bringen wenn man zum Beispiel den Inhalt des Frontends in Dateien zwischenspeichert, um zu vermeiden das alle Websitebetrachtungen die Datenbank belasten. Eine Website die sich nur alle paar Monate mal ändert, kann somit fast ausschließlich ohne Datenbankzugriffe auskommen. Auch dies ist Caching und dabei gibt es einige Punkte die beachtet werden müssen. Der Hauptpunkt dabei ist die Gültigkeit des gecachten Inhalts. Woher weiss ich wann so eine Datei für mein Frontend nicht mehr den aktuellen Inhalt hat? Ich habe ja kein „Änderungsdatum“ des Datensatzes in der Datenbank, wie beim Browsercache und selbst wenn ich eines mit speichern würde, so müsste ich den Datensatz dann trotzdem aus der Datenbank holen und habe somit nichts gewonnen. So manch einer mag nun auf die Idee kommen das die erstellten Dateien einfach in einem bestimmten Rhythmus via Cronjob oder ähnlichem neu erstellt werden. Das funktioniert in manchen Anwendungen auch, hat aber auch einige Nachteile. Bei oben genannter Website (die sich kaum ändert) würde das sehr gut funktionieren, bedeutet aber gleichzeitig auch wieder mehr Abfragen als nötig und wichtige Änderungen werden auf der Website erst nach den nächsten Cache-lösch-Zyklus sichtbar. Eine erweiterte Variante davon wäre, die Dateien mit einer Lebensdauer zu versehen. Dann hätte man für unterschiedliche Dateien unterschiedliche Möglichkeiten und man kann beim Aufruf der Website prüfen ob der Cache noch gültig ist und ggf. die Daten direkt in der Anfrage des Users neu generieren. Dann würden die Daten nur aus der Datenbank abgefragt werden, wenn die Gültigkeit abgelaufen ist und die langsamere Variante bekommt nur der allererste Aufruf zu spüren. Die beste Möglichkeit um zu testen ob der Cache noch gültig ist, ist es gar nicht zu testen. Das heisst also man hält die erstellten Dateien permanent auf dem neusten Stand. Da kommt sicher die Frage auf „wie soll das denn gehen?“. Nun, ein minütlicher Cronjob der die Dateien neu generiert ist natürlich Blödsinnig und würde den Server wahrscheinlich mehr belasten also ohne Cache zu arbeiten. Also müssen wir am anderen Ende ansetzten, am Backend, dort wo die Daten geändert werden. Wir müssen also bei jeder Datenänderung die entsprechende betroffenen Cache-Dateien entweder direkt aktualisieren oder aber deren Gültigkeit auf 0 setzen. Da stellt sich die Frage „soll ich jetzt den Datenaustausch zwischen Applikation und Datenbank belauschen und bei jeden INSERT oder UPDATE“ die Cache-Aktualisierung durchführen?“. Die Antwort darauf lautet „Jein“. Ja im Bezug auf „bei jedem INSERT und UPDATE die Cache-Aktualisierung durchführen“ und nein im Bezug auf das lauschen. Ganz wichtig hierbei ist nämlich die Applikations-Struktur. Habe ich meine Applikation in einem ordentlichen objektorientiertem Design erstellt, zum Beispiel mit einem guten Framework und einem OR-Mapper, dann fällt es leicht eine Zwischenschicht zwischen Applikation und Datenbank zu setzen, die den Cache verwaltet und anhand der Datenbankänderungen entsprechend aktualisiert. Bei prozeduraler Programmierung kann das ganze leider je nach Struktur und Größe des Programms um einiges Aufwendiger werden.
    Haben wir dieses dann umgesetzt, ist das ganze schon fast perfekt, aber nur fast. Leider kann man sich nicht immer darauf verlassen, dass die eigene Anwendung die einzige Möglichkeit ist, die Daten zu verändern. Unser Cache bekommt aber nur Änderungen mit, die auch mit unserer Applikation gemacht wurden. Man sollte also als Hintertürchen die verschiedenen Möglichkeiten kombinieren, um ein für sich funktionierendes Gesamtkonzept zu bekommen.

    Happy Caching!


  • #2
    danke =)

    Kommentar


    • #3
      Der Nikolaus spricht mit dem Datenbankcaching einen interessanten Punkt an. Im Falle, dass ich folgende Query schreibe:

      PHP-Code:
      SELECT FROM tabelle WHERE gueltig_ab NOW() AND gueltig_bis NOW() 
      ... ist es doch vertretbar, dass ich auf die interne Funktion NOW() zurückgreife? Schließlich benötige ich einen sekundengenauen Vergleich.

      Kommentar


      • #4
        Vertretbar ist das sicherlich, du musst dir halt einfach im klaren darüber sein das die Abfrage nicht gecachet werden kann. Caching macht hier aber auch nicht viel Sinn, denn die Abfrage wird ja nicht mehrmals in der selben Sekunde ausgeführt oder?

        Kommentar


        • #5
          Nein, das ist eher nicht die Regel. Rein theoretisch kann es zwar vorkommen, aber das sollte eher der Ausnahmefall bleiben. Soweit ich es nachvollziehen kann, macht das Caching in diesem Fall erst ab größeren Zeiträumen Sinn, bspw. ab Stunden-/Tages-Genauigkeiten.

          Kommentar


          • #6
            exactly, aber im Thread ging es ja ums Prinzip, es muss sich nicht zwangsläufig auf Zeiträume beziehen

            Kommentar


            • #7
              Die letzten beiden Kapitel des Artikels scheinen mir doch recht diskussionswürdig. Ich stimme damit überein, dass eine Backendänderung ein richtiger Zeitpunkt ist, das Chaching neu zu initiieren. IMHO kann das aber nur darin bestehen, die Information "neues Caching nötig" zu setzen, bspw. indem alte Cachedateien gelöscht werden. Das Problem das ich sehe, ist, dass das Backend die gesamte Frontend-Struktur nicht kennt, bzw. nur mit sehr viel Aufwand alle möglichen Zustände ermitteln und vorcachen kann.
              Ein paar Beispiele:

              - Ein Bild einer Sidebar wird ausgetauscht. Fortan müssen alle angefragten Inhaltsseiten einen neuen Pad einbinden

              - Die Ergebnisse einer freien Stichwortsuche sollen gecacht werden (komplett dynamische Seite)

              usw. Ein Weg kann sein, dass im Backend Cachedateien gelöscht werden und das FE zunächst eine passende Cachedatei aufzurufen versucht und bei Nichtfinden den Inhalt nativ erzeugt und die Ausgabe gleichzeitig in den Response und eine neue Cachedatei schreibt.

              Alternativ kann das Caching früher ansetzen und komplexe Berechnungen als Strukturen cachen und die letzte Ausgabe immer dynamisch erzeugt werden.


              Bleibt die Frage, wie man das Caching dynamischer Inhalte organisiert. Hier ist es sinnvoll, sich Schlüsselparameter zu suchen, die den Inhalt repräsentieren (z.B. relevante Requestparameter, Zustandsobjekte etc.). Mit bspw. einem Hash der serialisierten Attribute kann man sich daraus super einen Cache-Dateinamen zusammenbauen. Je nach Anwendung kann man zusätzlich ein Prefix oder einen Unterordner (eine Art Namespace) für bestimmte Module etc. verwenden. Das erleichtert nicht zuletzt auch das Löschen der entspr. Dateien.

              Eine weitere Überlegung kann man bzgl. browserseitig eingebundener Dateien (JS, CSS) und deren Benamung in Hinblick auf Caching anstellen. Gerade wo aus Optimierungs- oder Dynamisierungsgründen solche Dateien auch generiert werden, sollte man sich ein cleveres Prinzip ausdenken um bei Änderung einen neuen Dateinamen erzeugen zu können.
              --

              „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
              Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


              --

              Kommentar


              • #8
                Zitat von nikosch Beitrag anzeigen
                Eine weitere Überlegung kann man bzgl. browserseitig eingebundener Dateien (JS, CSS) und deren Benamung in Hinblick auf Caching anstellen. Gerade wo aus Optimierungs- oder Dynamisierungsgründen solche Dateien auch generiert werden, sollte man sich ein cleveres Prinzip ausdenken um bei Änderung einen neuen Dateinamen erzeugen zu können.
                Guter Punkt. Momentan handhabe ich es so, dass sämtliche CSS/JS-Dateien eine Versionsnummer im Namen haben, bspw. "javascript.0.0.1.js" oder "style.0.0.1.css". Was ich mir noch vorstellen könnte, ist, schlichtweg einen Zeitstempel im Namen zu platzieren.

                Kommentar


                • #9
                  schlichtweg einen Zeitstempel im Namen zu platzieren.
                  Ja. Nur nicht den Fehler machen und time() verwenden
                  --

                  „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                  Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                  --

                  Kommentar


                  • #10
                    Ich geh da nen andren weg:
                    Ich definiere eine versionsnummer (z.b. als konstante aus einer datei eingebunden) und hänge in den templates diese nummer an die js und css dateien, und zwar als parameter:
                    Code:
                    index.css?1.12
                    bei einem update wird die versionsnummer aktualisiert, und die seite ab sofort als
                    Code:
                    index.css?1.13
                    ausgeliefert. auf dem server ist der dateiinhalt inzwischen aktualisiert, und der parameter interessiert auf dem server nicht, auf dem clienten regt es aber ein neu-laden der datei an.

                    Kommentar


                    • #11
                      Zitat von Screeze Beitrag anzeigen
                      Ich geh da nen andren weg:
                      Ich definiere eine versionsnummer (z.b. als konstante aus einer datei eingebunden) und hänge in den templates diese nummer an die js und css dateien, und zwar als parameter:
                      Code:
                      index.css?1.12
                      bei einem update wird die versionsnummer aktualisiert, und die seite ab sofort als
                      Code:
                      index.css?1.13
                      ausgeliefert. auf dem server ist der dateiinhalt inzwischen aktualisiert, und der parameter interessiert auf dem server nicht, auf dem clienten regt es aber ein neu-laden der datei an.
                      Ja, genau so mache ich es auch

                      Kommentar


                      • #12
                        Dann sollte man aber sehr kleinteilige Versionsnummern verwenden, z.B.

                        [major].[minor].[timestamp]

                        , denn nicht jedes CSS-Fix rechtfertigt ja gleich einen Versionssprung.
                        --

                        „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                        Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                        --

                        Kommentar


                        • #13
                          Nja, who cares?

                          Für Kundenprojekte gibt es sowieso immer nur neue Versionen, die ihnen ausgeliefert werden, da ist mir das IMHO egal. (ja selbst für jeden noch so mini fix) dient einfach zur besseren Verwaltung, Übersicht & Doku

                          Kommentar


                          • #14
                            im zweifelsfall kann man den css und js dateien auch unabhängige versionsnummern gehen, die bei major updates trotzdem hochgezählt werden.

                            Kommentar


                            • #15
                              Das habe ich mir anfangs auch überlegt, aber dann drauf verzichtet, weil es dann zuviele "Abhängigkeiten/interne Versionsnummern/Strings" im System geben könnte.

                              1. Eigentliche versionsnr
                              2. jquery Version
                              3. css Version
                              4. JS Version

                              Da hab ich mir gedacht, wozu das ganze?
                              Sobald ich das mit ner neuen jQuery Version getestet habe und alles ok war=> neues Package erstellt (dadurch natürlich auch neue Versionsnummer und fertig )
                              Sobald es minimale CSS Änderungen gegeben hat, war natürlich auch ein neues Package fällig

                              Was nun, wenn man nebenbei auch noch paar Bugs gefixt hat?
                              Wieso zig Versionsnummern(Projekt, CSS,JS) verwalten wo sich dann am Ende niemand mehr auskennt..

                              Natürlich kann mans auch anders handhaben, aber ich wollte mir das nicht antun

                              Kommentar

                              Lädt...
                              X