WordPress propose deux mécanismes pour éviter de recalculer une donnée : l'interface des valeurs temporaires et le cache d'objets. Les deux s'emploient presque de la même façon, avec une clé, une valeur et une durée, ce qui conduit à les considérer comme interchangeables. Ils ne le sont pas. L'un garantit la persistance et survit au redémarrage du serveur, l'autre est bien plus rapide et peut disparaître à tout moment. Choisir entre transients et cache d'objets détermine si une donnée coûteuse sera recalculée dix fois par seconde ou une fois par heure, et si sa disparition passera inaperçue ou cassera une fonctionnalité.
Deux mécanismes, une même apparence
La confusion vient de leur ressemblance en surface : les deux exposent une fonction pour écrire une valeur avec une durée de vie et une fonction pour la relire. Les différences se situent dans les garanties offertes, dans le lieu de stockage et dans le comportement en cas d'échec. Une valeur temporaire est enregistrée dans la table des options de la base de données, donc sur disque, ce qui la rend durable mais coûteuse en lecture. Une valeur du cache d'objets vit en mémoire, ce qui la rend très rapide et volatile. Cette distinction gouverne tout le reste. Elle explique à la fois les usages recommandés de chacun et les incidents que produit leur confusion.
Le point qui déroute le plus est qu'en présence d'un cache d'objets persistant, les valeurs temporaires cessent d'être écrites en base et sont redirigées vers ce cache. Le même code produit donc des comportements très différents selon la configuration du serveur, ce qui explique les incidents survenant uniquement en production. Un développement testé sans cache d'objets, où les valeurs temporaires survivent indéfiniment en base, se comporte tout autrement sur un serveur où elles peuvent disparaître à la première pression mémoire. C'est la source d'incident la plus fréquente sur ce sujet, et elle se prévient en connaissant simplement ce mécanisme. Le développement gagne donc à se faire sur un environnement configuré comme la production, ce qui suppose de savoir ce que la production a réellement installé.
Cette interaction se comprend mieux replacée dans l'ensemble des couches empilées sur un site, que nous décrivons dans notre article sur les couches de cache d'une boutique. Le cache d'objets se situe au niveau applicatif, en dessous du cache de pages et au dessus de la base, et il traite les données plutôt que les rendus. Il ne remplace donc aucune des autres couches et il devient au contraire d'autant plus utile que le cache de pages ne peut pas s'appliquer, sur les parcours authentifiés notamment. Sur une boutique où la majorité des visiteurs sont connectés, il devient même la principale source d'optimisation disponible.

Ce que fait l'interface des valeurs temporaires
Une valeur temporaire est destinée à conserver un résultat coûteux pendant une durée déterminée, avec l'assurance qu'il sera toujours là au bout de quelques minutes. Sans cache d'objets persistant, elle est écrite dans la table des options avec une seconde entrée portant sa date d'expiration. Cette persistance est sa qualité principale : elle survit au redémarrage du serveur web, au redémarrage du service de mémoire et au déploiement d'une nouvelle version. Sur un traitement dont le recalcul prend plusieurs secondes, cette garantie change tout. Elle évite notamment qu'un redéploiement ne déclenche une vague de recalculs simultanés au pire moment.
Le prix à payer est le coût de lecture et d'écriture, qui suppose deux requêtes en base à chaque accès en l'absence de cache d'objets. Sur une valeur relue à chaque affichage de page, ce coût annule une partie du bénéfice. S'y ajoute un défaut connu : les valeurs expirées ne sont pas supprimées immédiatement mais lors d'un passage de nettoyage, ce qui laisse la table des options grossir sur les sites qui en créent beaucoup. Une table de plusieurs centaines de milliers de lignes ralentit l'ensemble du site, et ce cas se rencontre régulièrement sur les installations anciennes. Un contrôle du poids de cette table figure d'ailleurs parmi les premiers réflexes lors de la reprise d'un site lent.
Un point mérite une attention particulière : les valeurs temporaires sans expiration sont marquées comme devant être chargées automatiquement à chaque requête, ce qui les fait entrer dans le jeu d'options lu au démarrage. Une valeur volumineuse enregistrée ainsi est donc lue à chaque page, y compris celles qui n'en ont aucun usage. C'est une cause de lenteur particulièrement discrète, que l'on repère en listant les options chargées automatiquement et en les triant par taille, contrôle qui devrait figurer dans tout diagnostic de performance. Quelques centaines de kilooctets chargés inutilement à chaque requête représentent un coût permanent que rien ne compense.
Ce que fait le cache d'objets
Le cache d'objets conserve des données en mémoire pendant la durée de la requête, et entre les requêtes lorsqu'un service de mémoire partagée est installé et raccordé par une extension de liaison. Sans ce service, il ne persiste pas d'une requête à l'autre, ce qui limite son intérêt à la déduplication des lectures au sein d'un même affichage. Avec lui, il devient l'un des leviers de performance les plus efficaces d'une installation WordPress, en supprimant la quasi totalité des lectures répétées d'options et de métadonnées. La différence est particulièrement nette sur les pages d'administration, où le nombre de requêtes est le plus élevé.
WordPress l'emploie massivement en interne, sans que le développeur ait à s'en préoccuper : les options, les métadonnées de contenu, les termes de taxonomie et les résultats de certaines requêtes y transitent automatiquement. Cela signifie qu'une installation dotée d'un cache d'objets persistant voit son nombre de requêtes de base chuter spectaculairement, souvent d'un facteur cinq à dix sur les pages complexes. Ce gain est obtenu sans modifier une seule ligne de code applicatif, ce qui en fait l'intervention la plus rentable sur une installation chargée. Elle suppose seulement un serveur sur lequel on peut installer un service, ce qui exclut la plupart des hébergements mutualisés d'entrée de gamme.
La contrepartie est l'absence de garantie. Une valeur peut disparaître avant son expiration, si la mémoire vient à manquer, si le service redémarre ou si le cache est vidé. Tout code lisant une valeur du cache doit donc traiter le cas où elle est absente, et ce cas doit rester fonctionnel plutôt qu'exceptionnel. Un code supposant qu'une valeur écrite il y a dix secondes sera toujours là produit des erreurs intermittentes, impossibles à reproduire et particulièrement pénibles à diagnostiquer. La bonne façon d'écrire ce code consiste à traiter l'absence comme le cas normal et la présence comme une optimisation.
| Critère | Valeur temporaire | Cache d'objets |
|---|---|---|
| Stockage sans service dédié | Base de données | Mémoire de la requête |
| Stockage avec service dédié | Mémoire partagée | Mémoire partagée |
| Persistance garantie | Oui sans service dédié | Non |
| Coût de lecture | Élevé en base | Très faible |
| Survit à un redémarrage | Oui sans service dédié | Non |
| Usage typique | Résultat d'appel distant | Donnée relue souvent |
| Risque principal | Table des options gonflée | Disparition imprévue |
Réduction du nombre de requêtes par affichage après raccordement d'un cache d'objets persistant, sur une installation WordPress chargée d'extensions.
Comment ils interagissent
En présence d'un cache d'objets persistant, les valeurs temporaires y sont stockées et perdent leur garantie de persistance. Cette redirection est délibérée et cohérente, un cache mémoire étant bien plus rapide qu'une table de base. Elle a toutefois une conséquence que peu de développeurs anticipent : un traitement conçu en supposant qu'une valeur temporaire survivra une heure peut la voir disparaître au bout de trois minutes. Le code doit donc être écrit pour recalculer sans dommage, quelle que soit la configuration du serveur. Le test le plus simple consiste à vider le cache d'objets en pleine navigation et à vérifier que rien ne casse.
Une conséquence pratique concerne les traitements longs. Un import découpé en lots, conservant sa progression dans une valeur temporaire, se comporte parfaitement sur un serveur sans cache d'objets et peut perdre sa progression sur un serveur qui en dispose. Pour ce genre de besoin, la progression doit vivre dans une option ordinaire ou dans une table dédiée, et non dans un mécanisme de cache, quel qu'il soit. La distinction entre une donnée que l'on peut recalculer et une donnée que l'on ne peut pas perdre est la question centrale de tout le sujet. Y répondre pour chaque donnée avant d'écrire la moindre ligne évite l'essentiel des incidents rencontrés ensuite.
Une autre interaction mérite d'être connue : le vidage du cache d'objets, déclenché par une extension de performance ou par un déploiement, supprime toutes les valeurs temporaires en même temps. Sur un site dont plusieurs traitements dépendent de valeurs coûteuses à recalculer, ce vidage produit une pointe de charge immédiate, tous les recalculs se déclenchant simultanément. Prévoir un décalage aléatoire dans les durées d'expiration atténue ce phénomène et évite qu'une purge ne provoque un incident. Une variation de quelques pourcents autour de la durée nominale suffit à étaler les recalculs dans le temps.
Quand employer l'un plutôt que l'autre
La règle de décision tient en une question : que se passe t il si la valeur disparaît immédiatement après avoir été écrite. Si la réponse est un simple recalcul, le cache d'objets convient parfaitement et son coût de lecture bien plus faible en fait le meilleur choix. Si la réponse est une erreur, une perte de données ou un comportement incorrect, il ne faut employer ni l'un ni l'autre, mais un stockage durable assumé comme tel. Cette troisième voie est trop rarement envisagée, la question étant presque toujours posée comme un choix entre les deux mécanismes de cache.
Les valeurs temporaires conviennent bien aux résultats d'appels distants : cours de change, flux d'actualités, réponse d'une interface tierce, résultat d'une vérification externe. Ces données coûtent cher à obtenir, leur péremption n'a pas de conséquence grave, et leur persistance évite de solliciter le service distant à chaque affichage. Le point de vigilance porte sur le comportement en cas d'indisponibilité du service : conserver la dernière valeur connue plutôt que rien du tout, quitte à la marquer comme périmée, produit un site bien plus robuste. Une durée de vie courte assortie d'une durée de secours plus longue, employée uniquement en cas d'échec, constitue le montage le plus solide.
Le cache d'objets convient aux données relues très souvent au sein d'une même page ou de pages voisines : un menu construit à partir de la base, une configuration assemblée depuis plusieurs sources, le résultat d'une requête coûteuse affichée dans un bloc présent partout. Sur ces cas, le gain se mesure en dizaines de requêtes économisées par affichage. Le calcul est immédiat : dix requêtes économisées sur une page vue cinquante mille fois par mois représentent un demi million de requêtes en moins. Il convient également aux données propres à un utilisateur, à condition d'inclure son identifiant dans la clé, précaution évidente et régulièrement oubliée. Son oubli produit exactement le même symptôme qu'un cache de fragments mal réglé, à savoir des données d'un utilisateur affichées à un autre.
Les pièges de mise en œuvre
Le premier piège concerne le nom des clés. Il paraît anodin et il produit pourtant les incidents les plus difficiles à comprendre. Une clé trop générique entre en collision avec celle d'une autre extension, ce qui produit des valeurs incohérentes très difficiles à diagnostiquer. Un préfixe propre au projet est indispensable, et la longueur de la clé est limitée pour les valeurs temporaires, contrainte à connaître avant de construire des clés à partir de paramètres concaténés. Une empreinte des paramètres, plus courte et de longueur fixe, règle élégamment cette question. Elle rend en revanche la clé illisible, ce qui complique le diagnostic et justifie de conserver un préfixe explicite devant l'empreinte.
Le deuxième piège est la valeur de retour ambiguë. La fonction de lecture retourne une valeur particulière lorsque la clé est absente, valeur qui peut être confondue avec un contenu légitime lorsque la donnée mise en cache est elle même vide ou fausse. Sur une valeur pouvant valoir zéro ou une chaîne vide, il faut employer le mécanisme de détection prévu ou enregistrer une structure englobante. Ce détail produit des recalculs permanents que personne ne remarque, la page fonctionnant parfaitement tout en n'utilisant jamais son cache. Le contrôle consiste à compter les recalculs sur une centaine de requêtes successives, ce qui révèle immédiatement le problème.
Le troisième piège est l'invalidation. Une valeur mise en cache doit être supprimée lorsque la donnée sous jacente change, ce qui suppose d'identifier tous les événements susceptibles de la modifier. L'oubli produit un affichage périmé, incident classique après la modification d'un contenu. La parade la plus robuste consiste à inclure dans la clé un élément qui change avec la donnée, une date de modification par exemple, ce qui rend l'invalidation automatique et supprime la nécessité de purger explicitement. Cette technique demande un peu de réflexion et supprime définitivement une classe entière de bogues. Elle laisse en contrepartie des valeurs orphelines dans le cache, inconvénient sans gravité puisqu'elles expirent d'elles mêmes.
Mesurer et diagnostiquer
Le premier contrôle consiste à savoir si un cache d'objets persistant est en place, information que l'écran de santé du site indique et que la présence d'un fichier de liaison dans le répertoire de contenu confirme. Cette réponse conditionne l'interprétation de tout le reste, et elle est étonnamment souvent inconnue des équipes qui travaillent sur le site. Sur un serveur dont on dispose, l'installation de ce service et de son extension de liaison prend une demi journée et produit un gain immédiat. Sur un hébergement mutualisé, certains fournisseurs le proposent en option, ce qui mérite d'être vérifié avant de conclure à son indisponibilité.
Le deuxième contrôle porte sur le nombre de requêtes de base par page, avant et après. Une extension de profilage affiche ce nombre, ainsi que la liste des requêtes les plus lentes. Un passage de deux cents à quarante requêtes sur une page de catégorie constitue un résultat ordinaire après installation d'un cache d'objets. Ce chiffre doit être relevé avant toute intervention, faute de quoi on ne saura pas si l'installation a produit un effet, situation dans laquelle on se trouve plus souvent qu'on ne l'admet. Le relevé doit se faire sur les mêmes pages et dans les mêmes conditions, faute de quoi la comparaison ne signifie rien.
Le troisième contrôle porte sur la table des options. Une requête comptant les entrées dont le nom commence par le préfixe des valeurs temporaires, et mesurant leur poids total, révèle immédiatement les accumulations. Un nettoyage des entrées expirées, suivi d'un examen des plus volumineuses, fait partie de l'entretien courant d'un site WordPress, au même titre que la surveillance décrite dans notre article sur la manière de surveiller un WordPress en production. Ce nettoyage se planifie utilement, comme nous l'expliquons à propos de la manière de programmer une tâche récurrente propre. Reste à décider ce qui se passe quand le cache est vide au pire moment, juste après une purge et sous forte affluence, situation où une génération non protégée déclenche autant de calculs simultanés qu'il y a de visiteurs.
💬 0 commentaires
✍️ Laisser un commentaire
Créez un compte gratuit ou connectez-vous pour commenter.