Come funziona la memorizzazione nella cache degli oggetti?


21

Sto cercando una risposta definitiva qui. Quando la memorizzazione nella cache degli oggetti è abilitata, dove finiscono per vivere opzioni e transitori?

Per impostazione predefinita, entrambi sono archiviati nel database. Ma ho sentito alcuni riferimenti che memcache li memorizzerà altrove e APC farà completamente qualcos'altro. Dove, esattamente , questi dati verranno mantenuti in entrambi i casi?


2
L'articolo citato da @toscho è ora disponibile su archive.org: Exploring the WordPress Cache API
here

Risposte:


34

WordPress, per impostazione predefinita, ha una forma di "memorizzazione nella cache degli oggetti" ma la sua durata è solo un singolo caricamento della pagina.

Le opzioni sono in realtà un ottimo esempio di questo. Dai un'occhiata a questa risposta per maggiori informazioni. Il riassunto:

  1. Inizia una pagina
  2. Tutte le opzioni sono caricate con una semplice SELECT option_name, option_value from $wpdb->optionsdichiarazione
  3. Richieste successive per tali opzioni (ad es. Una chiamata per get_optionnon colpire mai il database perché sono archiviate con l'API della cache WP.

Le opzioni "vivono" sempre nel database e sono sempre persistite lì - questa è la loro fonte "canonica". Detto questo, le opzioni vengono caricate nella cache degli oggetti, quindi quando richiedi un'opzione c'è una probabilità del 99% che la richiesta non raggiunga mai il database.

I transitori sono un po 'diversi.

WordPress ti consente di sostituire l'API della cache con un drop-in , un file che viene inserito direttamente nella tua wp-contentcartella. Se si crea il proprio drop in nella cache o si utilizza un plug-in esistente , è possibile mantenere la cache degli oggetti più a lungo di un singolo caricamento della pagina. Quando lo fai, i transitori cambiano un po '.

Diamo un'occhiata alla set_transientfunzione 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? Se è vero, WordPress utilizza la cache degli oggetti anziché il database per archiviare i transitori. Quindi, come viene impostato su true? È tempo di esplorare come WP imposta la propria API della cache.

Puoi tracciare quasi tutto su wp-load.phpo wp-settings.php- entrambi sono cruciali per il processo bootstrap di WordPress. Nella nostra cache, ci sono alcune righe rilevanti in wp-settings.php.

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

Ricordi quel calo delle cose dall'alto? Diamo uno sguardo a 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' ) );
    }
}

Le linee relative alla funzione (quelli che riguardano $_wp_using_ext_object_cacheche altera come transitori sono memorizzati).

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;
}

se object-cache.phppresente nella directory dei contenuti, viene incluso e WP presume che tu stia utilizzando una cache esterna e persistente, impostata $_wp_using_ext_object_cachesu true.

Se stai usando un oggetto esterno, i transitori di cache lo useranno. Il che solleva la questione di quando utilizzare le opzioni rispetto ai transitori.

Semplice. Se hai bisogno che i dati persistano indefinitamente, usa le opzioni. Vengono "memorizzati nella cache", ma le loro fonti canoniche sono il database e non andranno mai via a meno che un utente non lo richieda esplicitamente.

Per i dati che devono essere archiviati per un determinato periodo di tempo, ma non è necessario che persistano oltre un determinato periodo di tempo, utilizzare i transitori. Internamente, WP proverà a utilizzare una cache di oggetti esterna e persistente se può altrimenti i dati andranno nella tabella delle opzioni e verranno spazzati via tramite psuedo-cron di WordPress quando scadono.

Alcune altre preoccupazioni / domande:

  1. Va bene fare un sacco di chiamate a get_option? Probabilmente. Incitano la chiamata a un overhead di funzione, ma probabilmente non colpirà il database. Il caricamento del database è spesso una delle maggiori preoccupazioni nella scalabilità delle applicazioni Web rispetto al lavoro svolto dalla tua lingua preferita per la generazione di una pagina.
  2. Come faccio a sapere se utilizzare i transitori rispetto all'API della cache? Se si prevede che i dati persistano per un determinato periodo, utilizzare l'API temporanea. Se non importa se i dati persistono (ad es. Non ci vuole molto per calcolare / recuperare i dati, ma non dovrebbe accadere più di una volta per caricamento della pagina) utilizzare l'API della cache.
  3. Tutte le opzioni sono davvero memorizzate nella cache su ogni pageload? Non necessariamente. Se si chiama add_optioncon l'ultimo argomento facoltativo in quanto nonon vengono caricati automaticamente. Detto questo, una volta recuperati una volta, entrano nella cache e le chiamate successive non colpiranno il database.

nitpick 1: non tutte le opzioni vengono caricate all'inizio della pagina, ma solo quelle contrassegnate "autoload = yes" quando vengono create. L'impostazione predefinita per quel parametro in add_option è 'yes' e la maggior parte degli autori di plug-in non si preoccupano di capire la differenza nell'uso di un 'no' che rende la tua affermazione praticamente vera.
Mark Kaplun il

Anche le opzioni non caricate automaticamente vengono memorizzate nella cache dopo essere state recuperate una volta. Potrebbero non essere caricati inizialmente, ma successivamente vanno nella cache degli oggetti. Anche le opzioni che non esistono sono memorizzate nella cache! github.com/WordPress/WordPress/blob/master/wp-includes/… Ho comunque aggiunto una nota sull'opzione di caricamento automatico.
chrisguitarguy,

quello era nitpick 2;)
Mark Kaplun il

Grazie per l'ottimo articolo e per il tempo riassumendo tutto ciò.
prosti,

5

Ci sono 4 tipi di cache che conosco

  1. Trivial: è sempre attivo e ha effetto prima che qualsiasi altra cache entri in gioco. Memorizza gli elementi memorizzati nella cache in un array php, il che significa che consuma memoria dalla sessione di esecuzione di php e che la cache viene svuotata al termine dell'esecuzione di php. vale a dire anche senza usare un'altra cache se si chiama get_option ('opt') due volte di seguito, si eseguirà una query DB solo la prima volta e la seconda volta che il valore verrà restituito dalla memoria.

  2. File: i valori memorizzati nella cache vengono archiviati in file da qualche parte nella directory principale. Credo che si sia rivelato non efficace in termini di prestazioni a meno che non si disponga di un disco molto veloce o di una memoria file mappata in memoria.

  3. APC (o altra cache basata su acceleratore php): i valori memorizzati nella cache vengono archiviati nella memoria del computer host e al di fuori dell'allocazione di memoria php. La più grande trappola potenziale è che non esiste un ambito di applicazione dei dati e se si eseguono due siti potenzialmente ciascuno può accedere ai dati memorizzati nella cache dell'altro o sovrascriverli.

  4. Memcache: è una cache di rete. È possibile eseguire il servizio di memorizzazione nella cache in qualsiasi punto della rete e probabilmente memorizza i valori nella memoria dell'host. Probabilmente non hai bisogno di memcache a meno che tu non abbia un bilanciamento del carico in azione.

A proposito, la memorizzazione nella cache degli oggetti è molto più della cache delle opzioni, memorizzerà quasi tutto ciò che è stato recuperato dal DB utilizzando l'API WP di alto livello.


So che la risposta è abbastanza vecchia, ma aggiungerei anche l'eccellente Redis .
Cranio,

@Cranio, hai ragione ma ... redis è fondamentalmente una variante di memcache con memoria, e quindi è un DB (NoSQL). Questo IMHO è in realtà un problema, poiché se il nodo non funziona o non può essere aggiornato, è possibile ottenere informazioni non aggiornate. Ha un'opzione per disattivare il comportamento simile al DB ma non sono sicuro che sia attivato o disattivato per impostazione predefinita.
Mark Kaplun,

È un sostituto perfetto per Memcached (anche meglio), cos'altro ti serve? Di gran lunga l'uso più comune che ho visto è proprio come un archivio di valori-chiave RAM (sì, a parte questo, i dati possono essere resi persistenti, il clustering è in arrivo e ha funzionalità di gestione delle code, ma tutti aggiungono Redis come un eccellente opzione di memorizzazione nella cache per WP)
Cranio

tutti possono anche saltare dal ponte;) ma la complessità aggiuntiva non è assolutamente necessaria per la memorizzazione nella cache
Mark Kaplun,

È completamente inutile; vuoi la cache RAM, Redis esegue la cache RAM, punto; e lo fa meravigliosamente. Non c'è assolutamente nessuna complessità aggiuntiva se non vuoi provarci. Quindi, signore, non riesco davvero a capire il tuo punto.
Cranio,

0

Le opzioni sono sempre archiviate nel database, mentre i transitori possono essere archiviati solo nella memoria condivisa se sono installati APC e un plug-in che implementa la memorizzazione nella cache APC in WP. Memcache utilizza anche la memoria.

Le opzioni sono anche memorizzate e caricate da lì quando possibile (in caso contrario, viene eseguita una query db).


0

Ottima domanda

Penso che la parte con come WordPress utilizza la WP_Object_Cacheclasse sia ancora mancante, quindi lo aggiungerò.

Dai documenti:

DEF: la cache degli oggetti di WordPress viene utilizzata per salvare viaggi nel database. La cache degli oggetti archivia tutti i dati della cache in memoria e rende disponibili i contenuti della cache utilizzando una chiave, che viene utilizzata per denominare e successivamente recuperare i contenuti della cache.

Ecco la WP_Object_Cachestruttura.

inserisci qui la descrizione dell'immagine

Nota + è pubblico, - privato, # protetto.

Si utilizza il stats()metodo per mostrare statistiche generali sull'oggetto cache globale e cosa c'è dentro. Ecco l'output:

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 )

Questo è ciò che ho ottenuto all'inizio di un modello come single.php.

Nota la variabile che ci interessa è: global $wp_object_cache.

Il privato il membro $cachedetiene i dati di cache effettivi.

Nella programmazione, le strutture della cache sono ovunque. In una forma semplice possono essere riconosciuti come coppia chiave-valore. Benne, strutture NoDB, indici di database. L'obiettivo finale di WordPress Object Cache non era quello di avere la struttura più semplice possibile, ma è ancora possibile riconoscere coppie di valori-chiave.

Da single.phpquando ero quando ho stampato la cache:

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

Ricevo un singolo post nella cache.

    [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
        )

L'oggetto sarebbe il valore e la chiave di memorizzazione nella cache sarebbe

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

Qui puoi controllare la $cache_keystruttura:

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:   }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.