Wie funktioniert das Cachen von Objekten?

21

Ich suche hier eine endgültige Antwort. Wo leben Optionen und Transienten, wenn die Objekt-Zwischenspeicherung aktiviert ist?

Standardmäßig werden beide in der Datenbank gespeichert. Aber ich habe einige Hinweise gehört, dass memcache sie woanders speichert und APC etwas ganz anderes macht. Wo genau werden diese Daten in beiden Fällen gespeichert?

EAMann
quelle
2
Der Artikel, den @toscho erwähnt, ist jetzt auf archive.org
hier

Antworten:

34

WordPress führt standardmäßig eine Form von "Objekt-Caching" durch, die Lebensdauer beträgt jedoch nur eine Seite.

Optionen sind tatsächlich ein wirklich gutes Beispiel dafür. Lesen Sie diese Antwort, um weitere Informationen zu erhalten. Die Zusammenfassung:

  1. Eine Seite beginnt
  2. Alle Optionen werden mit einer einfachen SELECT option_name, option_value from $wpdb->optionsAnweisung geladen
  3. Nachfolgende Anforderungen für diese Optionen (z. B. ein Aufruf, get_optionder die Datenbank niemals erreicht, weil sie mit der WP-Cache-API gespeichert werden).

Optionen "leben" immer in der Datenbank und werden dort immer beibehalten - das ist ihre "kanonische" Quelle. Das heißt, Optionen werden in den Objekt-Cache geladen. Wenn Sie also eine Option anfordern, besteht eine 99-prozentige Wahrscheinlichkeit, dass die Anforderung niemals die Datenbank erreicht.

Transienten sind etwas anders.

Mit WordPress können Sie die Cache-API durch ein Drop-In ersetzen - eine Datei, die direkt in Ihrem wp-contentOrdner abgelegt wird . Wenn Sie ein eigenes Cache-Drop-In erstellen oder ein vorhandenes Plug-In verwenden , können Sie den Objekt-Cache länger als eine einzelne Seite laden. Wenn Sie dies tun, ändern Sie die Transienten ein wenig.

Werfen wir einen Blick auf die set_transientFunktion in wp-includes/option.php.

<?php
/**
 * Set/update the value of a transient.
 *
 * You do not need to serialize values. If the value needs to be serialized, then
 * it will be serialized before it is set.
 *
 * @since 2.8.0
 * @package WordPress
 * @subpackage Transient
 *
 * @uses apply_filters() Calls 'pre_set_transient_$transient' hook to allow overwriting the
 *  transient value to be stored.
 * @uses do_action() Calls 'set_transient_$transient' and 'setted_transient' hooks on success.
 *
 * @param string $transient Transient name. Expected to not be SQL-escaped.
 * @param mixed $value Transient value. Expected to not be SQL-escaped.
 * @param int $expiration Time until expiration in seconds, default 0
 * @return bool False if value was not set and true if value was set.
 */
function set_transient( $transient, $value, $expiration = 0 ) {
    global $_wp_using_ext_object_cache;

    $value = apply_filters( 'pre_set_transient_' . $transient, $value );

    if ( $_wp_using_ext_object_cache ) {
        $result = wp_cache_set( $transient, $value, 'transient', $expiration );
    } else {
        $transient_timeout = '_transient_timeout_' . $transient;
        $transient = '_transient_' . $transient;
        if ( false === get_option( $transient ) ) {
            $autoload = 'yes';
            if ( $expiration ) {
                $autoload = 'no';
                add_option( $transient_timeout, time() + $expiration, '', 'no' );
            }
            $result = add_option( $transient, $value, '', $autoload );
        } else {
            if ( $expiration )
                update_option( $transient_timeout, time() + $expiration );
            $result = update_option( $transient, $value );
        }
    }
    if ( $result ) {
        do_action( 'set_transient_' . $transient );
        do_action( 'setted_transient', $transient );
    }
    return $result;
}

Hmmm $_wp_using_ext_object_cache? Wenn dies zutrifft, verwendet WordPress den Objekt-Cache anstelle der Datenbank, um Transienten zu speichern. Wie wird das nun wahr? Zeit zu erkunden, wie WP seine eigene Cache-API einrichtet.

Sie können fast alles auf wp-load.phpoder wp-settings.phpzurückführen - beides ist entscheidend für den Bootstrap-Prozess von WordPress. In unserem Cache befinden sich einige relevante Zeilen wp-settings.php.

// Start the WordPress object cache, or an external object cache if the drop-in is present.
wp_start_object_cache();

Erinnerst du dich an das Drop-In-Ding von oben? Werfen wir einen Blick wp_start_object_cachein wp-includes/load.php.

<?php
/**
 * Starts the WordPress object cache.
 *
 * If an object-cache.php file exists in the wp-content directory,
 * it uses that drop-in as an external object cache.
 *
 * @access private
 * @since 3.0.0
 */
function wp_start_object_cache() {
    global $_wp_using_ext_object_cache, $blog_id;

    $first_init = false;
    if ( ! function_exists( 'wp_cache_init' ) ) {
        if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
            require_once ( WP_CONTENT_DIR . '/object-cache.php' );
            $_wp_using_ext_object_cache = true;
        } else {
            require_once ( ABSPATH . WPINC . '/cache.php' );
            $_wp_using_ext_object_cache = false;
        }
        $first_init = true;
    } else if ( !$_wp_using_ext_object_cache && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
        // Sometimes advanced-cache.php can load object-cache.php before it is loaded here.
        // This breaks the function_exists check above and can result in $_wp_using_ext_object_cache
        // being set incorrectly. Double check if an external cache exists.
        $_wp_using_ext_object_cache = true;
    }

    // If cache supports reset, reset instead of init if already initialized.
    // Reset signals to the cache that global IDs have changed and it may need to update keys
    // and cleanup caches.
    if ( ! $first_init && function_exists( 'wp_cache_switch_to_blog' ) )
        wp_cache_switch_to_blog( $blog_id );
    else
        wp_cache_init();

    if ( function_exists( 'wp_cache_add_global_groups' ) ) {
        wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache' ) );
        wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
    }
}

Die relevanten Zeilen der Funktion (diejenigen, die sich darauf beziehen $_wp_using_ext_object_cache, ändern, wie Transienten gespeichert werden).

if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
    require_once ( WP_CONTENT_DIR . '/object-cache.php' );
    $_wp_using_ext_object_cache = true;
} else {
    require_once ( ABSPATH . WPINC . '/cache.php' );
    $_wp_using_ext_object_cache = false;
}

Wenn object-cache.phpes in Ihrem Inhaltsverzeichnis vorhanden ist, wird es eingeschlossen, und WP geht davon aus, dass Sie einen externen, beständigen Cache verwenden. Es wird $_wp_using_ext_object_cacheauf true gesetzt.

Wenn Sie einen externen Objekt-Cache verwenden, wird dieser von Transienten verwendet. Dies wirft die Frage auf, wann Optionen im Vergleich zu Transienten verwendet werden sollen.

Einfach. Wenn Sie Daten für unbegrenzte Zeit benötigen, verwenden Sie Optionen. Sie werden "zwischengespeichert", aber ihre kanonischen Quellen sind die Datenbank, und sie werden niemals verschwinden, es sei denn, ein Benutzer fordert dies ausdrücklich an.

Verwenden Sie für Daten, die für einen festgelegten Zeitraum gespeichert werden sollen, jedoch nicht länger als eine bestimmte Lebensdauer bestehen müssen, Transienten. Intern wird WP versuchen, einen externen, persistenten Objekt-Cache zu verwenden, wenn dies nicht möglich ist. Andernfalls werden Daten in die Optionstabelle verschoben und bei Ablauf über WordPress 'psuedo-cron gesammelt .

Einige andere Bedenken / Fragen:

  1. Ist es in Ordnung, eine Menge Anrufe zu tätigen get_option? Wahrscheinlich. Sie verursachen den Aufruf eines Funktions-Overheads, der die Datenbank jedoch wahrscheinlich nicht berührt. Das Laden von Datenbanken ist für die Skalierbarkeit von Webanwendungen oft ein größeres Problem als die Arbeit, mit der Ihre Sprache eine Seite erstellt.
  2. Woher weiß ich, dass ich Transienten im Vergleich zur Cache-API verwenden kann? Wenn Sie davon ausgehen, dass die Daten für einen festgelegten Zeitraum bestehen bleiben, verwenden Sie die transiente API. Wenn es keine Rolle spielt, ob die Daten weiterhin vorhanden sind (z. B. dauert es nicht lange, die Daten zu berechnen / abzurufen, aber es sollte nicht mehr als einmal pro Seitenladevorgang vorkommen), verwenden Sie die Cache-API.
  3. Werden alle Optionen wirklich auf jeder Seite zwischengespeichert? Nicht unbedingt. Wenn Sie add_optionmit dem letzten optionalen Argument aufrufen , werden nosie nicht automatisch geladen. Das heißt, sobald Sie sie einmal abrufen, werden sie in den Cache verschoben, und nachfolgende Aufrufe werden nicht in die Datenbank übernommen.
chrisguitarguy
quelle
Nitpick 1: Nicht alle Optionen werden beim Start der Seite geladen, sondern nur die, die beim Erstellen als "autoload = yes" markiert sind. Der Standardwert für diesen Parameter in add_option ist 'yes', und die meisten Plugin-Autoren bemühen sich nicht darum, den Unterschied bei der Verwendung eines 'no' zu verstehen, damit Ihre Aussage praktisch wahr wird.
Mark Kaplun
Selbst nicht automatisch geladene Optionen werden zwischengespeichert, nachdem sie einmal abgerufen wurden. Sie dürfen zunächst nicht geladen werden, werden aber danach in den Objekt-Cache verschoben. Auch nicht vorhandene Optionen werden zwischengespeichert! github.com/WordPress/WordPress/blob/master/wp-includes/… Ich habe jedoch einen Hinweis zur Autoload-Option hinzugefügt.
Chrisguitarguy
Das war Nitpick 2;)
Mark Kaplun
Vielen Dank für den tollen Artikel und für die Zeit, die all das zusammengefasst hat.
Prosti
5

Es gibt 4 Cachetypen, die ich kenne

  1. Trivial - Es ist immer aktiviert und wirkt sich aus, bevor ein anderes Caching ins Spiel kommt. Es speichert die zwischengespeicherten Elemente in einem PHP-Array, was bedeutet, dass es Speicher von Ihrer PHP-Ausführungssitzung verbraucht und dass der Cache geleert wird, nachdem die PHP-Ausführung beendet ist. dh auch ohne Verwendung eines anderen Caches, wenn Sie get_option ('opt') zweimal hintereinander aufrufen, führen Sie eine DB-Abfrage nur beim ersten und beim zweiten Mal durch, wenn der Wert aus dem Speicher zurückgegeben wird.

  2. Datei - Die zwischengespeicherten Werte werden in Dateien irgendwo in Ihrem Stammverzeichnis gespeichert. Ich glaube, es hat sich als nicht effektiv in Bezug auf die Leistung erwiesen, es sei denn, Sie haben einen sehr schnellen Datenspeicher mit Festplatten- oder Speicherzuordnung.

  3. APC (oder anderes auf PHP-Beschleunigern basierendes Caching) - Die zwischengespeicherten Werte werden im Speicher Ihres Host-Rechners und außerhalb Ihrer PHP-Speicherzuordnung gespeichert. Die größte potenzielle Gefahr besteht darin, dass keine Datenbereiche festgelegt werden. Wenn Sie zwei Standorte betreiben, kann jeder potenziell auf die zwischengespeicherten Daten des anderen zugreifen oder diese überschreiben.

  4. Memcache - es ist ein netzwerkbasierter Cache. Sie können den Caching-Dienst überall im Netzwerk ausführen und er speichert wahrscheinlich Werte im Host-Speicher. Sie benötigen wahrscheinlich keinen Memcache, es sei denn, Sie haben einen Lastenausgleich in Aktion.

Übrigens, Objekt-Caching ist viel mehr als Optionen-Caching. Es speichert fast alles, was mit der WP-API auf hoher Ebene aus der Datenbank abgerufen wurde.

Mark Kaplun
quelle
Ich weiß, die Antwort ist ziemlich alt, aber ich würde auch die ausgezeichneten Redis hinzufügen .
Cranio
@Cranio, Sie haben Recht, aber ... redis ist im Grunde eine Variante von Memcache mit Speicher und daher eine (NoSQL) -DB. Diese IMHO ist tatsächlich schlecht, als ob der Knoten ausfällt oder nicht aktualisiert werden kann. Es gibt eine Option zum Deaktivieren des DB-ähnlichen Verhaltens, aber ich bin nicht sicher, ob es standardmäßig aktiviert oder deaktiviert ist.
Mark Kaplun
Es ist ein perfekter Ersatz für Memcached (noch besser), was brauchen Sie sonst noch? Bei weitem die häufigste Verwendung, die ich gesehen habe, ist nur ein RAM-Schlüsselwertspeicher (ja, ansonsten können Daten persistent gemacht werden, Clustering ist unterwegs und verfügt über Funktionen zur Warteschlangenverwaltung, aber jeder fügt Redis als einen hervorragenden hinzu Caching-Option für WP)
Cranio
jeder kann auch von der
mark
Das ist völlig sinnlos; Sie wollen RAM-Caching, Redis macht RAM-Caching, Punkt; und es macht es wunderbar. Es gibt absolut keine zusätzliche Komplexität, wenn Sie es nicht wollen. Also, Sir, ich verstehe Ihren Standpunkt wirklich nicht.
Cranio
0

Optionen werden immer in der Datenbank gespeichert, während Transienten möglicherweise nur im gemeinsamen Speicher gespeichert werden, wenn APC und ein Plugin installiert sind, das APC-Caching in WP implementiert. Memcache verwendet auch Speicher.

Optionen werden ebenfalls im Speicher gespeichert und von dort geladen, wenn dies möglich ist (andernfalls wird eine Datenbankabfrage durchgeführt).

ein Trickpony
quelle
0

Gute Frage.

Ich denke, der Teil, in dem WordPress die WP_Object_CacheKlasse verwendet, fehlt noch, also werde ich das hinzufügen.

Aus den Dokumenten:

DEF: Der WordPress-Objekt-Cache wird zum Speichern von Fahrten in die Datenbank verwendet. Der Objekt-Cache speichert alle Cache-Daten im Speicher und stellt den Cache-Inhalt mithilfe eines Schlüssels zur Verfügung, mit dem der Cache-Inhalt benannt und später abgerufen wird.

Hier ist die WP_Object_CacheStruktur.

Bildbeschreibung hier eingeben

Hinweis + ist öffentlich, - privat, # geschützt.

Mit dieser stats()Methode zeigen Sie allgemeine Statistiken über das globale Cache-Objekt und dessen Inhalt an. Hier ist die Ausgabe:

Cache Hits: 110
Cache Misses: 98

Group: options - ( 81.03k )
Group: default - ( 0.03k )
Group: users - ( 0.41k )
Group: userlogins - ( 0.03k )
Group: useremail - ( 0.04k )
Group: userslugs - ( 0.03k )
Group: user_meta - ( 3.92k )
Group: posts - ( 1.99k )
Group: terms - ( 1.76k )
Group: post_tag_relationships - ( 0.04k )
Group: category_relationships - ( 0.03k )
Group: post_format_relationships - ( 0.02k )
Group: post_meta - ( 0.36k )

Dies ist, was ich zu Beginn einer Vorlage wie z single.php.

Beachten Sie die Variable , die wir interessiert sind , ist: global $wp_object_cache.

Der private Bereich, in dem sich das Mitglied befindet, $cacheenthält die eigentlichen Caching-Daten.

In der Programmierung gibt es überall Cache-Strukturen. In einer einfachen Form können sie als Schlüsselwertpaar erkannt werden. Buckets, NoDB-Strukturen, Datenbankindizes. Das ultimative Ziel von WordPress Object Cache war es nicht, eine möglichst einfache Struktur zu haben, aber dennoch können Schlüsselwertpaare erkannt werden.

Seit ich drin war, single.phpals ich den Cache gedruckt habe:

print_r($wp_object_cache->cache['posts']);

Ich bekomme einen einzelnen Beitrag zwischengespeichert.

    [last_changed] => 0.34169600 1481802075
    [get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075] => 0
    [2831] => WP_Post Object
        (
            [ID] => 2831
            [post_author] => 1 
            ... the cached post object goes here
        )

Das Objekt wäre der Wert und der Caching-Schlüssel wäre

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

Hier können Sie die $cache_keyStruktur überprüfen :

File: /wp-includes/post.php
4210: /**
4211:  * Retrieves a page given its path.
4212:  *
4213:  * @since 2.1.0
4214:  *
4215:  * @global wpdb $wpdb WordPress database abstraction object.
4216:  *
4217:  * @param string       $page_path Page path.
4218:  * @param string       $output    Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
4219:  *                                a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
4220:  * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
4221:  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
4222:  */
4223: function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
4224:   global $wpdb;
4225: 
4226:   $last_changed = wp_cache_get_last_changed( 'posts' );
4227: 
4228:   $hash = md5( $page_path . serialize( $post_type ) );
4229:   $cache_key = "get_page_by_path:$hash:$last_changed";
4230:   $cached = wp_cache_get( $cache_key, 'posts' );
4231:   if ( false !== $cached ) {
4232:       // Special case: '0' is a bad `$page_path`.
4233:       if ( '0' === $cached || 0 === $cached ) {
4234:           return;
4235:       } else {
4236:           return get_post( $cached, $output );
4237:       }
4238:   }
prosti
quelle