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

Performance

Cache d’objets partagé : le piège d’un multisite de 500 sites communaux

Sur un réseau multisite de 500 sites communaux, un préfixe de clé manquant faisait qu'un site lisait parfois les transients d'un autre. Architecture recommandée pour un cache Redis partagé sans fuite.

Par WordPress Développement • 13 décembre 2021 • 4 min de lecture • Aucun commentaire
Cache d'objets partagé : le piège d'un multisite de 500 sites communaux

« Pourquoi la mairie de la commune B voit-elle parfois s’afficher un bandeau d’alerte météo destiné à la commune A ? » Cette question, posée par un chargé de communication, a ouvert un audit qui a révélé un défaut d’architecture bien plus large qu’un simple bug d’affichage : sur ce réseau multisite regroupant les sites de 500 communes, l’objet de cache Redis partagé mélangeait, dans certaines conditions, les transients de sites différents.

Arborescence du réseau et du cache

Réseau multisite WordPress (500 sites)
├── Site 1 (commune-a.reseau.fr) — blog_id = 2
│   └── transient: alerte_meteo (censé être propre au site 2)
├── Site 2 (commune-b.reseau.fr) — blog_id = 3
│   └── transient: alerte_meteo (lu par erreur depuis le site 2 !)
├── ...
└── Instance Redis partagée (object-cache.php, un seul serveur)
    └── Espace de clés commun à tous les blog_id

Le point de vigilance sur un multisite tient au fait que WordPress isole nativement les données en base par préfixe de table (wp_2_options, wp_3_options…), mais que cette isolation ne se propage pas automatiquement au cache objet si l’implémentation ne le prévoit pas explicitement.

Où se cachait la fuite

Le plugin d’objet de cache Redis utilisé préfixait correctement les clés par blog_id pour l’immense majorité des groupes de cache. Mais un groupe personnalisé, ajouté par une extension tierce de gestion des alertes météo communales, avait été déclaré comme « global » via wp_cache_add_global_groups(), une fonction précisément conçue pour les données réellement partagées entre tous les sites du réseau (comme les options réseau). Le développeur de cette extension l’avait utilisée par erreur pour un cache qui, en réalité, devait rester local à chaque site.

L'essentiel à retenir : Un cache Redis partagé exige un préfixe par site sans exception ; Les groupes de cache globaux doivent rester une liste explicite et documentée ; Un audit de clés en production révèle vite les fuites silencieuses
// Erreur trouvée dans l'extension tierce :
wp_cache_add_global_groups( [ 'alertes_meteo' ] );

// Cette déclaration retire le préfixe blog_id pour tout ce groupe,
// rendant ses clés visibles et partagées par les 500 sites du réseau.

Concrètement, une clé alerte_meteo_du_jour écrite par le site de la commune A écrasait ou masquait la même clé pour les 499 autres sites, puisque le groupe global ne préfixe jamais par blog_id, contrairement aux groupes standards.

Architecture recommandée pour un cache Redis partagé à grande échelle

  • Une seule instance Redis peut parfaitement servir 500 sites, à condition que chaque clé porte un préfixe de site non ambigu, généré automatiquement par l’objet de cache et jamais contournable par une extension tierce.
  • La liste des groupes globaux doit rester courte, documentée, et revue à chaque ajout d’extension : en pratique, seuls les réglages réellement partagés au niveau réseau (comme les rôles utilisateurs réseau) justifient ce statut.
  • Un audit périodique des clés Redis, via redis-cli --scan --pattern couplé à un script qui vérifie la cohérence des préfixes blog_id, permet de détecter une fuite avant qu’un utilisateur ne la signale.

La correction appliquée

La correction a consisté à retirer alertes_meteo de la liste des groupes globaux, pour qu’il redevienne un groupe standard préfixé automatiquement par site. Un script de purge complète du cache Redis a ensuite été exécuté pour éliminer toute clé mal préfixée restante, suivi d’un contrôle manuel sur un échantillon de dix communes pour confirmer que chacune ne voyait plus que ses propres alertes.

wp redis flush --network
wp cache flush --url=commune-a.reseau.fr
wp cache flush --url=commune-b.reseau.fr

Ce qu’il faut vérifier avant chaque nouvelle extension

Depuis cet incident, toute extension tierce installée sur ce réseau passe par une revue de code ciblée sur un point précis : recherche de tout appel à wp_cache_add_global_groups() ou wp_cache_add_non_persistent_groups(), et validation explicite que l’usage est justifié. Cette vérification prend moins de cinq minutes par extension et a déjà permis d’écarter deux autres cas similaires avant leur mise en production.

Sur un multisite, un groupe de cache déclaré « global » par erreur n’est pas un ralentissement : c’est une fuite de données entre organisations qui n’ont rien à voir entre elles.

En résumé

Un cache d’objets Redis partagé entre 500 sites d’un même réseau multisite fonctionne parfaitement à condition que l’isolation par blog_id reste garantie sur chaque groupe de cache. Le risque ne vient généralement pas de Redis lui-même, mais d’une extension tierce qui déclare à tort un groupe comme global. Un audit de code ciblé sur cette fonction, répété à chaque nouvelle extension, reste la meilleure prévention contre ce type de fuite silencieuse.

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