Le WordPress d'aujourd'hui, décodé pour les développeurs

Performance

Un site média à 300 articles par jour : invalider sans tout vider

Architecture de purge ciblée par tag pour une rédaction publiant en continu, évitant l'effondrement du cache de page à chaque publication.

Par WordPress Développement • 9 juin 2023 • 4 min de lecture • Aucun commentaire
Un site média à 300 articles par jour : invalider sans tout vider

« make.wordpress.org » documente depuis longtemps le principe du cache de page en façade d’un site WordPress, mais reste silencieux sur un problème très concret dès qu’une rédaction publie à un rythme soutenu : que purger, exactement, quand un article sort ? Sur un site d’actualités qui publie environ trois cents articles par jour, soit une sortie toutes les cinq minutes en heures pleines, la question a une conséquence directe sur la charge serveur.

La réponse naïve — vider tout le cache de page à chaque publication — fonctionne très bien à faible fréquence. À raison d’une purge toutes les cinq minutes, elle devient une source de charge constante : chaque purge totale force la régénération de toutes les pages populaires (accueil, rubriques, pages tag) au prochain visiteur, simultanément, ce qui recrée à chaque fois un mini pic de charge sur PHP-FPM et la base de données.

Le problème structurel de la purge globale

Une purge globale traite de façon identique une brève note de dix lignes en bas de rubrique et un article d’ouverture qui apparaît sur l’accueil, dans trois rubriques et dans un widget « à la une ». Or l’immense majorité des trois cents publications quotidiennes n’a d’impact que sur une poignée de pages : sa propre URL, sa rubrique, éventuellement une page tag. Vider systématiquement l’intégralité du cache pour cela revient à reconstruire des milliers de pages qui n’ont strictement pas changé.

Le principe de l’invalidation par tag

L'essentiel à retenir : Purger tout le cache à chaque publication crée un pic de charge répété toute la journée ; Un système de tags associe chaque page cachée aux contenus qu'elle affiche ; Ne purger que les pages réellement concernées limite l'effet de bord

La solution retenue associe, au moment de la génération de chaque page, une liste de « tags de cache » représentant les contenus qui y apparaissent : l’identifiant de l’article, ses catégories, ses étiquettes, et un tag global pour l’accueil si l’article y figure. Cette liste est stockée par la couche de cache (ici Varnish, via l’en-tête Cache-Tag, mais le principe transpose directement à un cache FastCGI avec un stockage de correspondance dans Redis) :

add_action( 'template_redirect', function () {
    if ( is_singular( 'post' ) ) {
        $tags = [ 'post-' . get_the_ID() ];
        foreach ( get_the_category() as $cat ) {
            $tags[] = 'cat-' . $cat->term_id;
        }
        if ( is_sticky() ) {
            $tags[] = 'accueil';
        }
        header( 'Cache-Tag: ' . implode( ',', $tags ) );
    }
});

Au moment de la publication ou de la mise à jour d’un article, seuls les tags concernés sont purgés, via une requête BAN Varnish ciblée sur l’en-tête, ou via une commande de suppression des clés Redis correspondantes pour un cache FastCGI :

add_action( 'save_post_post', function ( $post_id ) {
    $tags_a_purger = [ 'post-' . $post_id ];
    foreach ( get_the_category( $post_id ) as $cat ) {
        $tags_a_purger[] = 'cat-' . $cat->term_id;
    }
    purger_cache_par_tags( $tags_a_purger );
});

Arborescence de l’architecture retenue

Nginx (edge, TLS)
 └── Varnish (cache HTTP, tags via Cache-Tag)
      └── PHP-FPM (WordPress)
           └── MySQL
Purge :
 wp-admin (save_post) --HTTP PURGE ciblé--> Varnish
                       --purge par tag uniquement--> pages concernées

Le cas particulier de la page d’accueil

La page d’accueil reste le point sensible de ce modèle : elle affiche potentiellement n’importe lequel des trois cents articles du jour, ce qui rendrait son tag quasiment toujours invalidé. Le compromis retenu a été d’accepter un TTL court et fixe pour l’accueil seule (60 secondes), plutôt que de la purger à chaque publication, ce qui limite sa fraîcheur perçue tout en supprimant l’essentiel de la charge de purge.

Ce que ce modèle a changé concrètement

  • Le nombre de pages régénérées à chaud par publication est passé d’environ 4 000 pages (cache global) à une quinzaine en moyenne (article, rubrique, tags, pagination de rubrique).
  • Les pics de charge CPU corrélés aux publications, visibles auparavant sur le tableau de bord de supervision toutes les cinq à dix minutes, ont disparu du graphique.
  • Le taux de cache-hit global mesuré sur 24 heures est passé de 78 % à 96 %, l’essentiel du site restant servi depuis Varnish en continu.

Purger large est confortable à mettre en place, mais c’est le trafic qui paie la facture, publication après publication.

Notre verdict

L’invalidation par tag demande un effort de conception initial réel — définir la granularité des tags, s’assurer qu’aucun contenu affiché n’échappe au marquage — mais elle change fondamentalement le comportement d’un site à publication intensive. Pour une rédaction qui publie une poignée d’articles par jour, une purge globale reste largement suffisante et plus simple à maintenir ; au-delà d’une certaine cadence, elle devient un vrai risque de stabilité qu’il vaut mieux traiter en amont plutôt qu’après le premier incident de charge.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi