Categories
Technisches

WordPress mit Object Cache (memcached/Redis) für Entwickler

Zielgruppe

Entwickler von WordPress Themes und/oder Plugins, die $wpdb benutzen und sich jetzt wundern, warum die Website spinnt.

Intro – Caching

Caching beschleunigt Webapplikationen – so auch WordPress. Es gibt einen Schwung Caches, welche alle ihre Eigenarten haben. Für den Entwickler eines WordPress Plugins oder eines WordPress Themes ist dabei besonders der Object Cache (memcached oder Redis) zu beachten.

  • Viele andere Caches funktionieren im Hintergrund, ohne dass der Programmierer sich Gedanken um die Invalidierung machen muss
  • Komplette Seiten-Caches müssen wohlüberdacht sein und liegen eher im Verantwortungsbereich des Seitenbetreibers

Hier soll es also um die Object Caches (z.B. memcached) gehen und was man bei der Programmierung von Applikationen unter WordPress dafür beachten muss.

Funktionsweise von Object Caches

Object Caches sind einfache Key/Value-Speicher. Wenn man zum Beispiel mit einer aufwändigen Berechnung und vielen Datenbankabfragen ein Ergebnis bekommen hat, dann kann man dieses zwischenspeichern, um es bei späteren Aufrufen der Seite wider verwenden zu können, ohne die Berechnung und die Datenbankabfragen noch einmal machen zu müssen.

Der errechnete Wert (z.B. „42“) wird dann unter einem Key (z.B. „Antwort“) im Cache gespeichert. Bei der Speicherung wird neben dem Key und dem Wert auch noch eine Lebenszeit angegeben, nachdem der Wert automatisch invalidiert wird. Gibt man keine Lebenszeit an, dann muss man sich darum kümmern, dass der Wert bei einer Änderung der zugrundeliegenden Daten automatisch invalidiert wird.

Object Caches in WordPress

Unter WordPress kann man die Funktionen benutzen:

Wichtig ist aber zu wissen, dass WordPress diese Funktionen auch selbst benutzt. Wenn kein Plugin installiert ist, welches einen Object-Cache bereitstellt, dann cacht WordPress die Werte nur für die Dauer des Aufrufs. Wird allerdings ein Caching-Plugin installiert, dann werden die Werte auch über Aufrufe hinweg gespeichert – und das kann dann bei unachtsamer Programmierung zu Problemen führen.

Wann Invalidieren von Daten notwendig ist

WordPress bietet verschiedene Abstraktionsebenen.

  • Auf der obersten Ebene haben wir ein paar Funktionen wie the_title() und so, mit denen wir einfach in Templates auf Daten zugreifen können. Diese Funktionen nutzen den Cache ohne unser zutun.
  • Eine Ebene darunter befinden sich die Funktionen, mit denen man auf die Daten zugreifen kann, die WordPress in der Datenbank gespeichert hat. Hier kann man auch Daten ändern. wp_update_user(), get_post_meta() und so. Auch diese Funktionen nutzen den Cache, und wenn man mit ihnen (mit den Update-Funktionen) Daten ändert, dann invalidieren sie auch automatisch den Cache.
  • Als unterste Ebene stellt WordPress aber die $wpdb-Klasse zur Verfügung, mit denen man mehr oder weniger direkt mit der Datenbank interagieren kann. Hier umgeht man den Cache. Für Daten, die man so aus der Datenbank holt wird nicht zuerst der Cache befragt, sondern direkt die Datenbank. Gleiches gilt auch für Updates: Der Cache wir nicht invalidiert.

Das bedeutet, dass man bei der Nutzung der wpdb-Klasse vorsichtig sein muss. Ein Beispiel verdeutlicht das:

Beispiel

Zuerst schauen wir uns an, wie das funktioniert, wenn man die Funktionen eines höhren Abstraktionslevels benutzt:

  • Ein Benutzer schaut sich einen Post an. Dieser wird durch get_post() o.ä. aus der Datenbank geholt. Da das potentiell aufwändig ist wird das Ergebnis der Datenbankabfrage im Cache abgelegt.
  • Ein weiterer Benutzer schaut sich den gleichen Post an. WordPress holt die Daten nicht mehr aus der Datenbank, sondern aus dem Cache.
  • Mittels wp_update_post() wird der Post geändert. WordPress kümmert sich automatisch darum, dass der Cache invalidiert wird.
  • Ein dritter Benutzer schaut sich den Post an. Er wird wieder aus der Datenbank geholt, denn es gibt ja keinen gültigen Cache-Eintrag mehr für diesen Post. Das Ergebnis wird wieder im Cache abgelegt für den vierten Benutzer

Jetzt das Gleiche, nur dass wir zum Update des Posts nicht wp_update_post() benutzen, sondern direkt mit $wpdb arbeiten:

  • (identisch) Ein Benutzer schaut sich einen Post an. Dieser wird durch get_post() o.ä. aus der Datenbank geholt. Da das potentiell aufwändig ist wird das Ergebnis der Datenbankabfrage im Cache abgelegt.
  • (identisch) Ein weiterer Benutzer schaut sich den gleichen Post an. WordPress holt die Daten nicht mehr aus der Datenbank, sondern aus dem Cache.
  • Mittels wpdb wird der Post geändert. Da wir die Caching-Schicht umgehen bekommt der Cache nichts von der Änderung mit und der Cache wird nicht invalidiert.
  • Ein dritter Benutzer schaut sich den Post an. Da es noch einen gültigen Cache-Eintrag gibt bekommt der Benutzer die alte Version des Posts zu sehen. Das ist falsch uns sollte vermieden werden.

Man hat als Programmierer jetzt also drei Möglichkeiten:

  • Entweder benutzt man nur die Funktionen des höheren Abstraktionslevels (wp_update_post() o.ä.)
  • Oder man speichert seine Daten in eigenen Tabellen, so dass man sicher sein kann, dass WordPress nicht „von Haus aus“ darauf zugreift.
  • Oder man invalidiert den Cache nach Updates manuell

So invalidiert man Daten

Das kann man sich im Quelltext von WordPress schön anschauen, wie das die WordPress-eigenen Funktionen machen. In der Funktionsreferenz kann man nach „clean cache“ suchen, da findet sich sicherlich was passendes:

https://developer.wordpress.org/?s=clean+cache

Disclaimer

Dieser Text ist nur schnell für den Eigengebrauch runtergeschrieben und wurde nicht noch mal „Kontroll-gelesen“. Falls das jemand vor mir schafft werden Verbesserungen und Korrekturen gerne per Mail entgegen genommen.