Techniques avancées de mise en cache WordPress : Comment éviter une ruée vers le cache


La mise en cache est une technique essentielle pour optimiser les performances d’un site WordPress. Vous réduirez considérablement les temps de chargement des pages et du serveur en mettant en cache le contenu fréquemment consulté et en le servant à partir de la mémoire au lieu d’interroger la base de données à chaque fois.

Cependant, la mise en cache peut également entraîner des ruées vers le cache, qui ont l’effet inverse, ralentissant le site et augmentant la charge du serveur.

Qu’est-ce qu’une bousculade de cache ?

Une ruée vers le cache se produit lorsque plusieurs processus tentent de régénérer simultanément un contenu mis en cache de manière identique.

Par exemple, l’extrait de code ci-dessous affiche les trois publications les plus récentes sur chaque page de votre site. Si vous définissez le TTL du cache sur 15 minutes, chaque fois que le cache expire, tous les processus qui reconstruisent les pages essaieront de régénérer le même contenu simultanément, ce qui entraînera une vague de requêtes SQL qui peut ralentir le site ou même l’amener à une halte.

function my_stampeding_cache() {
    $posts = wp_cache_get( 'latest_posts' );

    // $posts will be false when the cache has expired
    if ( false === $posts ) {
        // get the latest 3 posts
        // See Section 70 - Querying - for tips on a more efficient query
        $args = array(
		'post_type'              => array( 'post' ),
		'nopaging'               => true,
		'posts_per_page'         => '3',
		'no_found_rows'          => true,
		'ignore_sticky_posts'    => true,
		'order'                  => 'DESC',
		'orderby'                => 'date',
	);

	// The Query
	$query = new WP_Query( $args );

        // save the query result for exactly 15 minutes
        wp_cache_set( 'latest_posts', $query->posts, 15 * MINUTES_IN_SECONDS );
    }

    // very simple list of post IDs
    foreach ( $posts as $post ) {
        echo '<li>' . intval( $post->ID ) . '</li>';
    }

}

Lorsque la durée de vie du cache expire lorsque diverses pages frontales sont reconstruites dans les processus PHP initiés par une requête d’URL, chacun des processus verra indépendamment le cache est disparu. En tant que tels, ils lanceront des requêtes SQL identiques et parfois parallèles qui peuvent être inutiles, ou bloqueront les ressources pendant un certain temps, dans le but d’obtenir les données sous-jacentes.

Cela peut mettre un site dans un mode cyclique où il ralentit périodiquement car d’autres requêtes doivent attendre. Il peut également commencer à évoluer pour gérer tous les processus PHP incomplets, ce qui ralentit le chargement des pages pour les utilisateurs et les éditeurs du site.

Pour éviter les ruées vers le cache, utilisez des techniques de mise en cache avancées qui garantissent qu’un seul processus régénère le cache à la fois.

Ajouter de la gigue au TTL

Dans le contexte de la mise en cache, le terme « jitter » est couramment utilisé pour désigner l’introduction de variations ou de fluctuations aléatoires dans une valeur ou un paramètre.

L’ajout de gigue à la valeur de durée de vie (TTL) est une technique utilisée pour atténuer les ruées vers le cache.

En introduisant de la gigue dans le TTL, nous introduisons des variations aléatoires dans le délai d’expiration des entrées de cache. Au lieu que toutes les entrées de cache expirent exactement au même moment, elles expirent à des moments légèrement différents en raison de la gigue ajoutée. Cela permet de répartir la charge plus uniformément et de réduire la probabilité de bousculades du cache.

Exemple sans gigue

L’entrée de cache A a un TTL de 60 secondes. L’entrée de cache B a un TTL de 60 secondes.

Les deux entrées ont été créées en même temps et expireront donc en même temps.

Lorsqu’elles expirent, les requêtes régénèrent toutes les entrées de cache désormais expirées en une seule fois, ce qui signifie un temps de réponse plus lent et une ruée sur les serveurs de cache.

Exemple avec gigue

L’entrée de cache A a un TTL de 60 secondes avec une gigue supplémentaire de ± 10 secondes. L’entrée de cache B a un TTL de 60 secondes avec une gigue supplémentaire de ± 10 secondes.

Les entrées ont été créées en même temps mais expirent à des moments légèrement différents en raison de la gigue.

A leur expiration, les demandes de régénération s’étalent sur une plage de 50 à 70 secondes.

En introduisant cette variation aléatoire, les demandes de régénération de cache sont réparties plus uniformément dans le temps, ce qui réduit les risques de tentatives de régénération simultanées et atténue les débandades de cache.

Voici un exemple de code pour illustrer comment la gigue dans TTL permet d’éviter les bousculades de cache :

function get_some_cached_data() {
    $key = 'cache_key';

    // Check if the transient cache entry exists
    $value = wp_cache_get( $key );

    if ( false !== $value ) {
        return $value;
    }

    // If the cache entry doesn't exist, generate a new value
    $value = generate_value();

    // Set the transient cache entry with the generated value and TTL
    $ttl = get_cache_ttl( 60 ); // TTL in seconds, with a jitter

    wp_cache_set( $key, $value, null, $ttl );

    return $value;
}

function get_cache_ttl( $ttl ) {
    // Add a jitter to the TTL
    $jitter = 0.1; // 10% jitter
    $jittered_ttl = $ttl + ( $ttl * $jitter * ( rand( 0, 1 ) ? 1 : -1 ) );

    return $jittered_ttl;
}

function generate_value() {
    // Simulate generating a new value
    sleep( 1 ); // Simulated delay in generating the value
    return 'Generated value';
}

// Example usage
$value = get_some_cached_data( $key );

Dans l’ensemble, l’ajout de gigue au TTL permet de lisser les modèles de trafic et d’atténuer les problèmes de performances potentiels causés par les bousculades du cache.

Mise en cache via wp-cron

L’un des moyens les plus efficaces d’éviter les ruées vers le cache est en utilisant wp-cron pour régénérer le cache à des intervalles prédéterminés ou en réponse à des événements spécifiques. Ici, un seul processus est responsable de la reconstruction du contenu, garantissant qu’il n’y a pas de duplication d’effort ou de conflit pour les ressources.

Il existe plusieurs stratégies de régénération du cache via wp-cronselon la nature et la fréquence des mises à jour.

1. Régénération programmée

Définissez un calendrier régulier de régénération du cache (horaire, quotidien ou hebdomadaire). Cette approche imite le mode TTL de mise en cache, mais au lieu de régénérer le cache immédiatement après son expiration, vous le régénérez à des intervalles prédéterminés.

2. Régénération basée sur les événements

Régénérez le cache en réponse à des événements spécifiques, comme lorsqu’un article passe de publié à non publié, ou lorsqu’un nouveau commentaire est ajouté à un article. Cette approche garantit que le cache est toujours à jour et évite la nécessité d’une régénération périodique.

3. Régénération à la demande

Régénérez le cache à la demande lorsqu’une publication est mise à jour. Ceci est utile pour les sites qui ont des mises à jour fréquentes, mais cela peut ralentir le processus d’édition, alors utilisez-le avec prudence.

Améliorer les performances du site frontal sur WordPress

Découvrez comment les images, les polices et les CDN contribuent à la vitesse et à la stabilité du site.

(nul)

Votre stratégie de régénération dépend des besoins spécifiques et des habitudes d’utilisation de votre site. Par exemple, si votre site contient beaucoup de contenu généré par les utilisateurs, envisagez d’utiliser la régénération basée sur les événements pour vous assurer que le cache est toujours à jour. Si votre site contient principalement du contenu statique, une régénération planifiée peut suffire.

Le code ci-dessous illustre des techniques pour régénérer les données mises en cache à l’aide de wp-cron. Cet échantillon :

  • Planifie une tâche pour générer une liste des 25 ID de publication les plus récents toutes les heures
  • Enregistre le résultat indéfiniment dans le cache d’objets
  • Planifie une mise à jour de la liste immédiatement lors de la publication d’un article
  • Récupère les données de publication sous-jacentes (généralement à partir du cache) lorsque les données sont accessibles à partir d’un modèle
<?php
// on init, hook the function to the action
add_action( 'my_regenerate_posts_cron', 'my_regenerate_posts' );

// and schedule the first (optional, particularly if you are using categories)
if ( ! wp_next_scheduled( 'my_regenerate_posts_cron' ) ) {
	wp_schedule_event( time(), 'hourly', 'my_regenerate_posts_cron' );
}

// action to regenerate on publish (you can also hook on transition instead)
add_action( 'publish_post', 'my_reschedule_cron_for_now' );

// scheduling function, if you are using category, then you'd need to extract that from the $post argument
function my_reschedule_cron_for_now() {
	// Clear any existing hourly cron, note this needs the same args (if any) as the scheduled event if you're passing a category
	wp_clear_scheduled_hook( 'my_regenerate_posts_cron' );
	// Reschedule the hourly updates, initiating an immediate regeneration.
	wp_schedule_event( time(), 'hourly', 'my_regenerate_posts_cron' );
}

// cron task to generate posts, it could have an optional set of params eg category
// this runs under wp_cron asynchronously
function my_regenerate_posts() {
	$cache_key = 'my_cache_key';    // cache key
	$some_url="http://example.com/url-with-posts/"; // URL to invalidate, optional

	// Your query code here
	$args = (
		'posts_per_page' => 25,
		'fields'         => 'ids',
		'post_type'      => ( 'post' ),
		'no_found_rows'  => true,
		'order'          => 'DESC',
		'orderby'        => 'date',
	);
	$query = new WP_Query( $args );

	// save it in a transient for a long time
	wp_cache_set( $cache_key, $query->posts );

	// optional for VIP Go if you have known endpoints
	wpcom_vip_purge_edge_cache_for_url( $some_url );

}

// code that gets the posts - it does not attempt to query if there are no posts
// this would be called from your widget, or theme, or plugin code
function my_get_posts() {
	$cache_key = 'my_cache_key';    // cache key
	$posts = ();   // posts array

	// get the cached data. Return an error if there's no data
	$ids = wp_cache_get( $cache_key );

	if ( false === $posts ) {
		my_reschedule_cron_for_now();
		return $posts;
	}

	// get the underlying post data (from cache usually)
	foreach ( $ids as $post_id ) {
		$posts() = get_post( $post_id );
	}

	return $posts;
}

Ce code définit plusieurs fonctions qui fonctionnent ensemble pour régénérer et récupérer les données mises en cache. Le my_regenerate_posts() La fonction est la fonction principale qui génère la liste des identifiants de publication et les enregistre dans un transitoire. Le my_reschedule_cron_for_now() la fonction est chargée de reprogrammer wp-cron événement lorsqu’un article est publié, garantissant que le cache est immédiatement régénéré.

Utilisation des fonctions WordPress VIP pour vider le cache périphérique

En plus d’utiliser wp-cron pour la régénération du cache, les clients WordPress VIP peuvent utiliser le Cache de page de la plate-forme VIP pour effacer le cache périphérique pour des URL spécifiques lorsque le cache est invalidé. La plateforme VIP vide automatiquement le cache des URL associées courantes lorsque le contenu est mis à jour. Cela inclut le lien permanent de la publication, la page d’accueil, les URL de taxonomie pour les termes associés et les URL de flux. Cela permet de maintenir le contenu de votre site à jour sans avoir à attendre que les caches expirent naturellement, le tout automatiquement sans autre configuration.

Il existe des cas où un contrôle plus fin est nécessaire, comme pour les URL qui ne sont pas automatiquement effacées, comme les routes personnalisées. Les URL individuelles peuvent être vidées avec wpcom_vip_purge_edge_cache_for_url( $url ) et la liste des URL automatiquement vidées peut être modifiée à l’aide de la wpcom_vip_cache_purge_{$post->post_type}_post_urls filtre. Pour plus de détails, veuillez consulter la documentation de l’API de cache.

Une mise en garde ici : cela n’est nécessaire que lorsque l’attente de l’expiration normale du cache peut ne pas convenir et que les URL des points de terminaison sont connues et finies. Pour contrôler la durée de vie du cache périphérique d’une ressource, utilisez la max-age entête.

Améliorer les performances de WordPress

Vous cherchez d’autres moyens d’améliorer les performances WordPress de votre entreprise ? Nous avons de nombreuses ressources intéressantes pour les développeurs qui souhaitent optimiser leurs sites WordPress.



<Voir les plus beaux thèmes