Wie funktioniert Caching?

freiberuflicher Programmierer

Wenn die Software oder Website nicht schnell genug lädt, verzögert das den Arbeitsablauf. Im besten Fall bekommt die Software von den Anwendern so liebevolle Spitznamen wie “Sanduhr-Anzeige-Programm”. Im schlimmsten Fall wird der Arbeitsablauf so stark verzögert, dass die zusätzlich benötigte Zeit die Firma viele tausende Euro kostet – und das oft nicht mal auffällt. Ganz besonders fällt das auf, wenn man Daten über das Netzwerk oder Internet austauscht.

Schnellere Ladezeiten

Die Lösung für dieses Problem in der Software- und Hardwareentwicklung heißt “Caching”. Das bedeutet, man geht davon aus, dass Daten, die demnächst benötigt werden, entweder auf dem Speichermedium in der Nähe liegen (räumlich) oder die benötigten Daten bereits kurz zuvor angefordert wurden (zeitlich).

Zum Beispiel: Wird in einem Steuerprogramm auf den Datensatz der ersten Rechnung zugegriffen, ist es wahrscheinlich, dass bald auf den Datensatz der zweiten Rechnung zugegriffen wird. Oder zeitlich gesehen: Wird die Startseite einer Webseite aufgerufen, wird sie wahrscheinlich bald wieder aufgerufen (auch von einem anderen Besucher). Damit die benötigten Daten nicht in mehreren Zugriffen oder Berechungsschritten bei jedem Aufruf neu zur Verfügung gestellt werden müssen, werden bereits berechnete Daten in einen Cache, also Zwischenspeicher geschrieben, auf den schnell zugegriffen werden kann. Das kann manuell gemacht werden (z.B. durch Zwischenspeichern der Ergebnisse in einer Datei) oder durch Hilfsprogramme wie Memcached oder Redis, welche die Daten unter einem Stichwort im Arbeitsspeicher ablegen (sog. Key-Value-Store).

Beispiel dynamische Homepage

Soweit eine sehr einfache und schnelle Lösung, die man mit jeder Programmiersprache umsetzen kann. Nur wo? Und auf welche Art? Ich möchte das anhand einer dynamischen Homepage, programmiert in PHP, erklären. Der Ablauf einer solchen Seite funktioniert folgendermaßen:

Der Nutzer ruft eine Seite auf, der Webserver nimmt die Anfrage entgegen, leitet die Anfrage an PHP weiter, dieses holt sich in den meisten Fällen Daten von einer SQL-Datenbank, formatiert die Daten für die Ausgabe, generiert daraus HTML und gibt es zurück an den Webserver. Dieser sendet das HTML zurück an den Nutzer. Sind auf der Webseite Bilder oder andere zusätzlich zu ladende Dateien enthalten, wird für jeden dieser Inhalte eine zusätzliche Anfrage an den Webserver gestellt, der diese Daten ausliefert.

Man sieht, es ist eine ganze Menge Rechenaufwand und gesendeter Daten nötig, um eine Webseite zu laden. Glücklicherweise kann man hier an vier Stellen Caching einsetzen:

  1. PHP bietet wie viele “interpretierte” Sprachen (d.h. nicht kompiliert, sondern erst beim Aufruf zu Zwischencode übersetzt) die Möglichkeit, den Zwischencode (Opcode) zu cachen. Die einfachste Methode dazu ist ein PHP-Modul zu aktivieren, den sogenannten Alternative PHP Cache (APC). Dieser speichert den generierten Zwischencode, um die Interpretation des PHP Codes zu ersparen.
  2. Werden Daten von einer SQL-Datenbank geholt, geschieht das über eine Anfrage als Text, den sogenannten “Query“. Dieser Query wird vom SQL-Server interpretiert und die Ergebnisse anschließend entsprechend der Anfrage vorbereitet und zurück gesendet. Werden die Ergebnisse zu einem Query in einem Cache abgelegt, so kann die Interpretation des Queries und das Vorbereiten der Daten übersprungen werden.
  3. Nachdem das HTML vom PHP generiert wurde, wird es via Webserver zurück an den Nutzer gesendet. Speichert man diese HTML-Datei in einem Cache, kann man sich den kompletten weiteren Prozess auf dem Webserver sparen. Allerdings muss hier darauf geachtet werden, dass die Webseite, solange sie sich im Cache befindet, “statisch” ist.
  4. Schlussendlich werden die zusätzlichen Daten (Bilder, Stylesheets, Javascripts …) vom Webserver an den Nutzer bzw. dessen Browser gesendet. Diese Daten können sehr groß werden und werden häufig nach jedem Klick auf der Seite benötigt. Damit diese Daten nicht bei jedem Aufruf neu abgefragt werden müssen, bietet der Browser die Möglichkeit, diese Daten lokal im Browsercache zu speichern. Dazu muss der Webserver an den Browser übermitteln, wie lange jeweilige Datei gültig ist. Dafür ist nur eine einfache Konfiguration notwendig.

Setzt man alle vier Caches ein, kann man die Seitenladezeiten um bis zu 98% senken! Natürlich erst beim zweiten Aufruf – denn der erste muss den Cache befüllen.

Wie lange sollte ein Cache gültig sein?

Allerdings kann Caching auch zu Problemen führen: Wie lange ist ein Cache gültig? Also wann müssen die Daten neu berechnet werden?

Um dieses Problem zu lösen, gibt es ein einfaches Standard-Vorgehen und ein komplexes, welches die Caches wirklich erst dann erneuert, wenn es wirklich notwendig ist. Die einfachste Möglichkeit besteht darin, dass zu einem Eintrag im Cache gespeichert wird, zu welchem Zeitpunkt dieser ungültig wird. Wird dann versucht auf den Eintrag zuzugreifen, wird zunächst überprüft, ob dieser immer noch gültig ist. Sollte er nicht mehr gültig sein, so werden die Daten erneut aufbereitet. Die “Lebensdauer” eines Eintrags ist in diesem Fall ein Schätzwert, der je nach Art des Eintrags stark variieren kann. Das kann zu Problemen führen, wenn beispielsweise Daten in der Datenbank verändert wurden, aber die zuvor generierte Datei immer noch im Cache liegt. Dann werden veraltete Daten ausgeliefert. In diesem Fall muss man den Cache auf andere Art und Weise löschen. Dadurch erhöht sich allerdings wieder der Aufwand.

Die zweite Möglichkeit umgeht dieses Problem auf Kosten des Vorbereitungsaufwandes: Es wird für Operationen, die Daten verändern, definiert, welche Caches als ungültig erklärt (invalidiert) werden sollen. Wird beispielsweise auf der Startseite einer Webseite ein neuer Eintrag hinzugefügt, müssen alle Caches, die sich auf dem Weg zwischen Datenbank und dem Webseitenbesucher befinden, welche die Daten für die Startseite abrufen und berechnen, invalidiert werden. Das erfordert einen sehr hohen Konzeptionsaufwand, bietet dafür allerdings zwei immense Vorteile: Erstens werden keine veralteten Daten mehr ausgeliefert, da sie laufend erneuert werden sobald sich etwas ändert. Zweitens können die Daten beim Invalidieren direkt neu generiert und in den Cache geladen werden. Somit entfällt die Wartezeit beim Erstaufruf nicht auf einen Anwender, sondern wird im Hintergrund vom Programm selbst übernommen.

Zusammengefasst kann man sagen, dass Caching in jedem Projekt immer an irgendeiner Stelle Sinn macht. Selbst wenn man nur ein einfaches Caching für wenige Daten nutzt, kann die gewonnene Zeit bereits die User Experience verbessern und ein schnelleres und effektiveres Arbeiten mit der Software ermöglichen.

Links:

memcached.org
redis.io
php.net

Rückmeldungen