Soll ich die Transient-API zum Speichern von HTML-Zeichenfolgen oder -Objekten verwenden?

18

Angenommen, es gibt ein Plugin, das 20 verwandte Beiträge (für jeden Beitrag) mit einer sehr komplexen Abfrage anzeigt. Mit den Daten dieser Abfrage wird dann ein komplexes HTML-Layout erstellt. Beachten Sie außerdem, dass das Plugin öffentlich ist und auf jedem Server mit jeder Konfiguration installiert werden kann.

So etwas wie:

/* complex and large query */
$related_posts = get_posts( ... );

$html_output = '';
foreach($related_posts as $key => $item) {
     /* complex layout rendering logic (but not as slow as the previous query) */   
     $html_output .= ...;
}

Meine Fragen sind also:

  • Was ist der sicherste und korrekteste Weg, solche Daten zwischenzuspeichern?
  • Soll ich die Transient-API zum Zwischenspeichern von $related_postsArrays oder $html_outputZeichenfolgen verwenden? Wenn ich eine $html_ouputZeichenfolge zwischenspeichern werde, erreicht sie dann eine maximale Größe? Soll ich es vielleicht gzipen, bevor ich es speichere?
  • Soll ich hier überhaupt Transient API verwenden?
Marvin3
quelle

Antworten:

18

Soll ich hier überhaupt Transient API verwenden?

Nein.

In einer Standardversion von WordPress werden Installationstransienten in der Tabelle wp_options gespeichert und nur während der Kernaktualisierungen bereinigt. Angenommen, Sie haben 50.000 Posts, das sind 50.000 zusätzliche Zeilen in der Optionstabelle. Offensichtlich sind sie auf autoload = no eingestellt, so dass nicht Ihr ganzer Speicher verbraucht wird, aber es gibt eine weitere Einschränkung.

Das Autoload-Feld in der Optionstabelle hat keinen Index, was bedeutet, dass der Aufruf von wp_load_alloptions()einen vollständigen Tabellenscan durchführen wird. Je mehr Zeilen Sie haben, desto länger dauert es. Je öfter Sie in die Optionstabelle schreiben, desto weniger effizient sind die internen Caches von MySQL.

Wenn sich die zwischengespeicherten Daten direkt auf einen Beitrag beziehen, ist es besser, sie in Post-Meta zu speichern. Dies erspart Ihnen auch jedes Mal eine Abfrage, wenn Sie den zwischengespeicherten Inhalt anzeigen müssen, da Post-Meta-Caches (normalerweise) während des Post-Abrufs in WP_Query vorbereitet werden.

Ihre Datenstruktur für den Meta-Wert kann variieren, Sie können einen Zeitstempel haben und Ihre teure Abfrage durchführen, wenn der zwischengespeicherte Wert veraltet ist, ähnlich wie sich ein Transient verhalten würde.

Ein weiterer wichtiger Aspekt ist, dass WordPress-Transienten in Umgebungen mit permanentem Objekt-Caching flüchtig sein können. Wenn Sie also Ihre zwischengespeicherten Daten 24 Stunden lang in einem Übergang speichern, gibt es keinerlei Garantie dafür, dass sie in 23 Stunden, 12 Stunden oder sogar 5 Minuten verfügbar sind. Das Objekt-Cache-Backend für viele Installationen ist ein speicherinterner Schlüsselwertspeicher wie Redis oder Memcached. Wenn nicht genügend Speicher für neuere Objekte zugewiesen ist, werden ältere Elemente entfernt. Dies ist ein enormer Gewinn für den Meta-Storage-Ansatz.

Die Invalidierung kann auch intelligenter sein. Warum machen Sie verwandte Posts-Caches in X Stunden ungültig? Liegt es daran, dass sich einige Inhalte geändert haben? Ein neuer Beitrag wurde hinzugefügt? Ein neuer Tag wurde zugewiesen? Abhängig von Ihrer "komplexen und großen Abfrage" können Sie NUR dann die Ungültigerklärung wählen, wenn etwas passiert ist, das die Ergebnisse Ihrer Abfrage verändert.

Sollte ich die Transient-API verwenden, um das Array $ related_posts oder die Zeichenfolge $ html_output zwischenzuspeichern? Wenn ich die Zeichenfolge $ html_ouput zwischenspeichern werde, wird sie eine maximale Größe erreichen? Soll ich es vielleicht gzipen, bevor ich es speichere?

Es hängt stark von der Größe Ihres Strings ab, da dies die Daten sind, die zwischen PHP, MySQL usw. fließen werden. Sie müssen sich sehr bemühen, die MySQL-Grenzen zu erreichen, aber Memcached hat zum Beispiel das Standardlimit pro Objekt nur 1 mb.

Wie lange dauert Ihre "komplexe Layout-Rendering-Logik" tatsächlich? Führen Sie es durch einen Profiler, um es herauszufinden. Es ist sehr wahrscheinlich, dass es nie zu einem Engpass kommt.

In diesem Fall würde ich empfehlen, die Beitrags-IDs zwischenzuspeichern. Nicht die WP_Post-Objekte, da diese den gesamten Beitragsinhalt enthalten, sondern nur ein Array von Beitrags-IDs. Verwenden Sie dann einfach a WP_Querymit a, post__inwas zu einer sehr schnellen MySQL-Abfrage per Primärschlüssel führt.

Das heißt, wenn die Daten, die pro Element benötigt werden, ziemlich einfach sind, vielleicht Titel, Thumbnail-URL und Permalink, können Sie nur diese drei speichern, ohne den Overhead eines zusätzlichen Roundtrips zu MySQL und ohne den Overhead des Zwischenspeicherns von sehr langem HTML Streicher.

Wow das sind viele Worte, hoffe das hilft.

Kovshenin
quelle
12

Nicht jeder WP-Code ist öffentlicher Code

Wenn du etwas öffentliches veröffentlichen willst , dann sind alle Dinge, die Kovshenin sagte, vollkommen gültig.

Anders verhält es sich, wenn Sie privaten Code für sich oder Ihr Unternehmen schreiben.

Externer Objekt-Cache ist auf jeden Fall ein großer Vorteil

Das Festlegen eines externen permanenten Objektcaches wird nach Möglichkeit dringend empfohlen .

All die Dinge, die in der Antwort von Kovshenin zu Transienten und MySQL gesagt wurden, sind sehr wahr, und wenn man bedenkt, dass WP selbst und eine Reihe von Plugins den Objekt-Cache nutzen ... dann ist die Leistungsverbesserung, die Sie erhalten haben, den (kleinen) Aufwand für die Einrichtung absolut wert ein modernes Cache-System wie Redis oder Memcached.

Zwischengespeicherte Werte sind möglicherweise nicht vorhanden: Das ist in Ordnung

Außerdem ist ein externer Objektcache nicht zuverlässig. Sie sollten sich niemals darauf verlassen, dass ein Transient vorhanden ist. Sie müssen sicherstellen, dass es funktioniert, wenn zwischengespeicherte nicht dort sind, wo sie sein sollten.

Cache ist keine Speicherung, Cache ist Cache.

Cache gezielt nutzen

Siehe dieses Beispiel:

function my_get_some_value($key) {
   // by default no cache when debug and if no external object_cache
   $defUse = ! (defined('WP_DEBUG') && WP_DEBUG) && wp_using_ext_object_cache();
   // make the usage of cache filterable
   $useCache = apply_filters('my_use_cache', $defUse);
   // return cached value if any
   if ($useCache && ($cached = get_transient($key))) {
     return $cached;
   }
   // no cached value, make sure your code works with no cache
   $value = my_get_some_value_in_some_expensive_way();
   // set cache, if allowed
   $useCache and set_transient($key, $value, HOUR_IN_SECONDS);

   return $value;
}

Einen Code wie folgt verwenden, in Ihrem privaten Website können Site - Performance verbessern viel , vor allem , wenn Sie viele Benutzer haben.

Beachten Sie, dass:

  • Standardmäßig wird der Cache nicht verwendet, wenn das Debugging aktiviert ist, also hoffentlich in Ihrer Entwicklungsumgebung. Glauben Sie mir, Cache kann das Debuggen zur Hölle machen
  • Standardmäßig wird der Cache auch nicht verwendet, wenn WP nicht für die Verwendung eines externen Objektcaches eingestellt ist. Dies bedeutet, dass das gesamte mit MySQL verbundene Problem nicht besteht, da Sie bei der Verwendung von MySQL keine Transienten verwenden. Eine wahrscheinlich einfachere Alternative wäre die Verwendung von wp_cache_*Funktionen . Wenn also kein externer Cache eingerichtet ist, befindet sich der Cache im Speicher und die Datenbank ist nie beteiligt.
  • Die Verwendung des Cache kann gefiltert werden, um einige Randfälle zu behandeln, die auftreten können

Keine Webscale wenn kein Cache

Sie sollten nicht versuchen, Geschwindigkeitsprobleme mit dem Cache zu lösen. Wenn Sie Geschwindigkeitsprobleme haben, sollten Sie Ihren Code überdenken.

Zum Skalieren einer Website mit Webscale ist jedoch ein Cache erforderlich .

Und oft (aber nicht immer) ist der kontextsensitive Fragment-Cache viel flexibler und geeigneter als das aggressive Fullpage-Caching.

Deine Fragen:

Soll ich hier überhaupt Transient API verwenden?

Kommt drauf an .

Verbraucht Ihr Code viele Ressourcen? Wenn nicht, ist möglicherweise kein Cache erforderlich. Wie gesagt, ist nicht nur eine Frage der Geschwindigkeit. Wenn Ihr Code schnell ausgeführt wird, für einige Benutzer jedoch eine Menge CPU und Arbeitsspeicher erforderlich ist, was passiert, wenn 100 oder 1000 Benutzer gleichzeitig angemeldet sind?

Wenn Sie feststellen, Cache wäre eine gute Idee ..

... und ist öffentlicher Code: wahrscheinlich nein . Sie können erwägen, selektiv zu cachen, wie in meinem obigen Beispiel im öffentlichen Code, aber in der Regel ist es besser, wenn Sie solche Entscheidungen den Implementierern überlassen.

... und ist privater Code: sehr wahrscheinlich ja . Aber auch für privaten Code ist das selektive Zwischenspeichern immer noch eine gute Sache, zum Beispiel für das Debuggen.

Denken Sie jedoch daran, dass Sie mit diesen wp_cache_*Funktionen auf den Cache zugreifen können, ohne dass die Gefahr besteht , dass die Datenbank verschmutzt wird.

Sollte ich die Transient-API verwenden, um das Array $ related_posts oder die Zeichenfolge $ html_output zwischenzuspeichern?

Es hängt von vielen Dingen ab. Wie groß ist die Saite? Welchen externen Cache verwenden Sie? Wenn Sie Posts zwischenspeichern möchten, kann das Speichern der ID als Array eine gute Idee sein. Das Abfragen einer anständigen Anzahl von Posts anhand ihrer ID ist recht schnell.

Schlussbemerkungen

Transiente API ist wahrscheinlich eines der besten Dinge von WordPress. Dank der Plugins, die Sie für jede Art von Cache-Systemen finden können, wird es zu einer blöden einfachen API für eine große Anzahl von Software, die unter der Haube arbeiten kann.

Außerhalb von WordPress ist eine solche Abstraktion, die mit einer Reihe verschiedener Caching-Systeme von Anfang an funktioniert und es Ihnen ermöglicht, mühelos von einem System zu einem anderen zu wechseln, sehr schwer zu finden.

Sie können mich selten sagen hören, dass WordPress besser ist als andere moderne Dinge, aber die vorübergehende API ist eines der wenigen Dinge, die ich vermisse, wenn ich nicht mit WordPress arbeite.

Sicher ist der Cache schwer, löst keine Codeprobleme und ist kein Wundermittel, aber er ist etwas, das Sie benötigen , um eine Website mit hohem Datenverkehr zu erstellen, die funktioniert.

Die WordPress-Idee, eine unteroptimierte MySQL-Tabelle für den Cache zu verwenden, ist ziemlich verrückt, aber es ist nicht besser, sich vom Cache fernzuhalten, nur weil WordPress dies standardmäßig tut.

Sie müssen nur verstehen, wie die Dinge funktionieren, und dann Ihre Wahl treffen.

gmazzap
quelle
2

In den vorherigen Antworten wurde bereits das obligatorische " Es hängt davon ab " hervorgehoben, dem ich voll und ganz zustimme.

Ich möchte jedoch eine Empfehlung hinzufügen, basierend darauf, wie dies am besten in dem oben beschriebenen Szenario " angenommen " wird.

In diesem Fall würde ich nicht Transients verwenden , sondern Post Meta , da letzteres den Vorteil hat: Control .

Da Sie Daten pro Post zwischenspeichern müssen, hängt die Datenmenge, die Sie zwischenspeichern, von der Anzahl der Posts ab und wächst mit der Zeit. Sobald Sie eine bestimmte Anzahl von Beiträgen überschritten haben, können Sie die Speichergrenzen Ihres Objekt-Caches überschreiten, und die zuvor zwischengespeicherten Daten werden aus dem Speicher gelöscht, bevor sie abgelaufen sind. Dies kann zu einer Situation führen, in der Sie einen großen Zustrom von Besuchern haben, bei der jeder Besucher bei jeder Seitenanforderung das "überkomplexe SQL" auslöst und Ihre Website völlig aus dem Ruder läuft.

Wenn Sie die Daten in Ihrem Post-Meta-Cache speichern, können Sie nicht nur steuern, wie sie gespeichert und abgerufen werden, sondern auch genau steuern, wie sie aktualisiert werden. Sie würden hierfür einen Cron-Job hinzufügen, der nur in Zeiträumen ausgeführt wird, in denen weniger bis gar kein Datenverkehr zur Site besteht. Die "langsame Abfrage" wird also von echten Benutzern der Site nie angetroffen, und Sie können sie sogar vorab laden, sodass die Arbeit bereits erledigt ist, wenn der erste Besucher auftaucht.

Denken Sie daran, dass jedes Caching ein Kompromiss ist! Deshalb lautet die übliche Antwort "Es kommt darauf an." und warum es keinen "heiligen caching grail" gibt.

Alain Schlesser
quelle