web-dev-qa-db-fra.com

Comment fonctionne la mise en cache d'objets?

Je cherche une réponse définitive ici. Lorsque la mise en cache des objets est activée, où vivent les options et les transitoires?

Par défaut, les deux sont stockés dans la base de données. Mais j'ai entendu dire que memcache les stockerait ailleurs et qu'APC ferait autre chose. Où, exactement , ces données seront-elles conservées dans les deux cas?

21
EAMann

WordPress, par défaut, fait une forme de "Object Caching" mais sa durée de vie n'est qu'un chargement de page.

Les options en sont un très bon exemple. Découvrez cette réponse pour plus d'informations. Le résumé:

  1. Une page commence
  2. Toutes les options sont chargées avec une simple instruction SELECT option_name, option_value from $wpdb->options
  3. Les requêtes suivantes pour ces options (par exemple, un appel à get_option ne touchent jamais la base de données car elles sont stockées avec l'API de cache WP.

Les options sont toujours "actives" dans la base de données et y sont toujours persistées - c'est leur source "canonique". Cela dit, les options sont chargées dans le cache d'objets. Ainsi, lorsque vous en demandez une, il y a 99% de chances que la demande ne parvienne jamais dans la base de données.

Les transitoires sont un peu différents.

WordPress vous permet de remplacer l'api du cache par un drop-in -, un fichier placé directement dans votre dossier wp-content. Si vous créez votre propre cache de cache ou utilisez un existantplugin , vous pouvez faire en sorte que le cache d'objets persiste plus longtemps que le chargement d'une seule page. Lorsque vous faites cela, transitoires, changez un peu.

Jetons un coup d'oeil à la fonction set_transient dans 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? Si c'est vrai, WordPress utilise le cache d'objets au lieu de la base de données pour stocker les transitoires. Alors, comment est-ce que cela devient vrai? Il est temps d'explorer comment WP configure sa propre API de cache.

Vous pouvez tracer presque tout le contenu de wp-load.php ou wp-settings.php - deux éléments cruciaux pour le processus d'amorçage de WordPress. Dans notre cache, il y a quelques lignes pertinentes dans wp-settings.php.

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

Vous souvenez-vous de cette chute en haut? Jetons un coup d'oeil à wp_start_object_cache dans 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' ) );
    }
}

Les lignes pertinentes de la fonction (celles relatives à $_wp_using_ext_object_cache qui modifient la façon dont les transitoires sont stockés).

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

si object-cache.php existe dans votre répertoire de contenu, il est inclus et WP suppose que vous utilisez un cache persistant externe: il définit $_wp_using_ext_object_cache sur true.

Si vous utilisez un cache d’objet externe, les transitoires l’utiliseront. Ce qui soulève la question de savoir quand utiliser les options par rapport aux transitoires.

Simple. Si vous souhaitez que les données persistent indéfiniment, utilisez les options. Ils sont "mis en cache", mais leurs sources canoniques sont la base de données et ils ne disparaîtront jamais à moins que l'utilisateur ne le demande explicitement.

Pour les données qui doivent être stockées pendant une durée définie, mais ne doivent pas nécessairement persister au-delà d'une période transitoire d'utilisation spécifiée. En interne, WP tentera d'utiliser un cache d'objets persistant externe s'il le peut, sinon les données entreront dans la table d'options et seront récupérées via psuedo-cron de WordPress lorsqu'elles expirent.

Quelques autres préoccupations/questions:

  1. Puis-je faire une tonne d'appels à get_option? Probablement. Ils encourent l'appel d'une surcharge de fonction, mais celle-ci ne sera probablement pas touchée par la base de données. La charge de la base de données est souvent un problème plus important dans l'évolutivité des applications Web que dans le travail de votre langue de choix générant une page.
  2. Comment savoir utiliser les transitoires par rapport à l'API de cache? Si vous vous attendez à ce que les données persistent pendant une période définie, utilisez l'API transitoire. Si la persistance des données n'a pas d'importance (par exemple, le traitement/l'extraction des données ne prend pas longtemps, mais cela ne devrait pas se produire plus d'une fois par chargement de page), utilisez l'API de cache.
  3. Toutes les options sont-elles vraiment mises en cache sur chaque chargement de page? pas nécessairement. Si vous appelez add_option avec son dernier argument facultatif sous la forme no, ils ne sont pas chargés automatiquement. Cela dit, une fois que vous les avez récupérées une fois, elles sont placées dans le cache et les appels suivants ne parviennent pas à la base de données.
34
chrisguitarguy

Il y a 4 types de cache que je connais

  1. Trivial - Il est toujours activé et prend effet avant toute autre mise en cache. Il stocke les éléments mis en cache dans un tableau php, ce qui signifie qu'il utilise la mémoire de votre session d'exécution php et que le cache est vidé une fois l'exécution de php terminée. c'est-à-dire que même sans utiliser d'autre cache, si vous appelez get_option ('opt') deux fois de suite, vous ne ferez une requête de base de données que la première fois et la deuxième fois, la valeur sera renvoyée de la mémoire.

  2. Fichier - Les valeurs mises en cache sont stockées dans des fichiers quelque part dans votre répertoire racine. Je pense que cela s’est avéré inefficace en termes de performances, sauf si vous avez un disque très rapide ou un stockage de fichiers mappé en mémoire.

  3. APC (ou autre mise en cache basée sur un accélérateur php) - Les valeurs mises en cache sont stockées dans la mémoire de votre ordinateur hôte et en dehors de votre allocation de mémoire php. Le plus grand écueil potentiel est qu'il n'y a pas de périmètre de données et que si vous exécutez deux sites, chacun d'entre eux peut potentiellement accéder aux données mises en cache de l'autre ou les écraser.

  4. Memcache - c'est un cache basé sur le réseau. Vous pouvez exécuter le service de mise en cache n'importe où sur le réseau et celui-ci stocke probablement des valeurs dans la mémoire de son hôte. Vous n'avez probablement pas besoin de Memcache, sauf si vous avez un équilibrage de charge en action.

BTW, la mise en cache des objets est beaucoup plus que la mise en cache des options, elle stockera presque tout ce qui a été extrait de la base de données à l’aide de l’API de haut niveau WP.

5
Mark Kaplun

Excellente question.

Je pense que la partie concernant la manière dont WordPress utilise la classe WP_Object_Cache est toujours manquante, je vais donc l'ajouter.

De la docs:

DEF: Le cache d'objets WordPress est utilisé pour économiser sur les déplacements dans la base de données. Le cache d'objets enregistre toutes les données du cache dans la mémoire et rend le contenu du cache disponible à l'aide d'une clé qui permet de nommer et d'extraire ultérieurement le contenu du cache.

Voici la structure WP_Object_Cache.

 enter image description here 

La note + est publique, - privée, # protégée.

Vous utilisez la méthode stats() pour afficher des statistiques générales sur l'objet de cache global et sur ce qu'il contient. Voici la sortie:

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 )

C’est ce que j’ai eu au tout début d’un modèle tel que single.php.

Notez que la variable qui nous intéresse est: global $wp_object_cache.

Le privé dont le membre $cache contient les données de mise en cache réelles.

En programmation, les structures de cache sont partout. Sous une forme simple, ils peuvent être reconnus comme une paire de valeurs de clé. Buckets, structures NoDB, index de base de données. L'objectif ultime de WordPress Object Cache n'était pas d'avoir la structure la plus simple possible, mais des paires de valeurs clés pouvaient toujours être reconnues.

Depuis que j'étais en single.php quand j'ai imprimé le cache:

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

Je reçois un seul post en 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'objet serait la valeur, et la clé de mise en cache serait

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

Ici, vous pouvez vérifier la structure $cache_key:

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:   }
0
prosti

Les options sont toujours stockées dans la base de données, tandis que les transitoires ne peuvent l'être que dans la mémoire partagée si APC et un plug-in implémentant la mise en cache APC dans WP sont installés. Memcache utilise également la mémoire.

Les options sont également stockées en mémoire et chargées à partir de là lorsque cela est possible (sinon, une requête de base de données est effectuée).

0
onetrickpony