Découvrez nos offres pour faire du digital le levier de votre croissance !
Téléchargez le Guide Ultime de gestion de projet digitale pour vous aider à piloter vos transformations et faire les bons choix !
La gestion du cache pour un site web a donc pour but d’améliorer le temps de réponse du site et d’éviter la surcharge du serveur. Ce temps de réponse est devenu un levier direct d’augmentation du trafic, notamment par le ranking réalisé par Google. Une gestion de cache performante permet également de réduire les requêtes et les calculs pour les serveurs. Il s’agit donc d’une démarche d’éco-conception des solutions web modernes.
Dans le but de rester compétitif face aux autres CMS, Drupal a mis en place une politique de cache performante. Véritable pierre angulaire des performances d'un site, le cache Drupal est basé sur des tags et est lié aux structures de contenu. Il est interfaçable avec des applicatifs de type Redis en back ou Varnish en front et offre plein d'outils pour l'utiliser et l'invalider.
Après ces quelques mots d’introduction, il est temps de découvrir les modules du cœur inclus dans ce système.
Le fonctionnement de Drupal inclut des modules du cœur qui fournissent toutes les fonctionnalités de base et qui sont :
Ce module de cache statique par page ne fonctionne que pour les utilisateurs anonymes. La première fois qu’un utilisateur anonyme demande une page, celle-ci est stockée puis réutilisée. Il est essentiellement recommandé pour les sites web de petite et taille moyenne.
Si votre site web propose un contenu personnalisé à des utilisateurs anonymes (dynamique, par session, comme un panier d'achat par exemple) vous devez désactiver ce module. En effet, le module Internal Page Cache part du principe que les pages sont identiques pour tous les utilisateurs anonymes.
Attention, ce module provoque des soucis avec les caches contexts et les caches max-age. Je vous recommande de le désactiver par défaut sauf pour les sites vitrines les plus simples et statiques.
Ce module, fourni par Drupal, est recommandé pour les sites web de toutes les tailles. Il met en cache les pages sans les parties personnalisées. Il est utile pour tous les utilisateurs (anonymes et authentifiés).
Le module Dynamic Page Cache améliore les performances car il permet de mettre en cache les pages à contenu dynamique. Comment ? Les pages demandées par les utilisateurs (anonymes ou authentifiés) sont stockées lors de la première demande et peuvent ensuite être réutilisées. Les parties personnalisées sont exclues : elles sont transformées automatiquement en placeholders.
En fonction de la configuration de votre site et de la complexité de certaines pages, ce module peut augmenter considérablement la vitesse du site, même pour les utilisateurs authentifiés.
Il est plutôt rare d'interagir directement avec la Cache API de Drupal, en mettant, délibérément, un élément en cache ou en le récupérant du cache par exemple. En général, notre code a pour but de rendre des éléments (blocs, entités, formulaires, etc.) qui seront renvoyés sous forme de tableaux de rendu (render arrays). Tous ces tableaux de rendu sont traités et finissent par être envoyés dans un objet Response (HtmlResponse la plupart du temps).
Nous pouvons interagir ou voir le cache œuvre à travers ces 2 niveaux :
Dans les render arrays ou tableaux de rendu, des métadonnées de mise en cache (cacheability metadata) sont insérées et vont influencer la mise en cache du rendu de ces tableaux. Les cacheability metadata permettent de déterminer la validité du cache en fonction des dépendances, du contexte et du temps écoulé depuis la mise en cache.
Lorsqu'un moteur de rendu (Renderer) convertit le tableau de rendu en HTML, il part de l'élément situé à l'intérieur et travaille vers l'extérieur. Chaque étape est mise en cache et comprend l'élément et ses enfants. Les futures passes de rendu de ce même arbre utiliseront des versions en cache d'un élément dès que c’est possible afin d'accélérer les choses.
L'interaction la plus courante avec le cache dans Drupal se fait par le biais de ces cacheability metadata, en les modifiant, en les ajoutant ou en invalidant du cache par leur biais.
Toutes les cacheability metadata définies dans les tableaux de rendu remontent jusqu'au Response object et permettent aux modules du cœur Internal Page Cache et Dynamic Page Cache de mettre en cache de manière valide une réponse à une requête.
De cette façon, les futures requêtes peuvent contourner toute la logique nécessaire à la construction de la page et renvoyer simplement une version en cache - en supposant qu'elle soit toujours valide.
Les caches Reverse Proxy comme Varnish ou CloudFlare sont des exemples de Response Caching.
Saviez-vous qu’il est possible d’effectuer une mise en cache manuelle avec la cache API ? Certes, le besoin n’est pas très courant mais il est toujours utile de connaître la procédure. Les éléments qui ne sont pas liés à un tableau de rendu peuvent être mis en cache à l'aide de la Cache API.
Par exemple, le code qui effectue des requêtes vers une API externe pourrait mettre en cache les résultats de cette requête localement et les réutiliser pendant une période déterminée. Cela augmente les performances de la page en éliminant une ou plusieurs requêtes qui prennent beaucoup plus de temps qu’une simple recherche d'un enregistrement dans le cache.
Maintenant, passons à la partie la plus importante : l’utilisation de la cache API. Rien de plus simple, il suffit des suivre ces quelques étapes :
$cid = 'mymodule_example:' . \Drupal::languageManager()
->getCurrentLanguage()
->getId();
$data = NULL;
$cache = \Drupal::cache()->get($cid);
if ($cache) {
$data = $cache->data;
}
else {
$data = my_module_complicated_calculation();
\Drupal::cache()->set($cid, $data);
}
Vous souhaitez aller plus loin dans l'utilisation de la Cache API ? Alors, vous pouvez utiliser des Cache bins pour séparer les domaines de cache, supprimer des caches, ou encore, découvrir comment utiliser un autre backend que la base de données ?
Les Cacheability metadata se composent de 3 propriétés :
Les cache tags fournissent un moyen de suivre les éléments du cache qui dépendent de données gérées par Drupal.
C'est essentiel car le même contenu peut être réutilisé de nombreuses façons et donc il est impossible de savoir à l'avance où un contenu va être utilisé. Dans tous les endroits où le contenu est utilisé, il peut être mis en cache. Ce qui signifie que le même contenu peut être mis en cache à des dizaines d'endroits. Les cache tags permettent de répondre à la question de comment invalider tous les caches où un contenu particulier est présent.
Par exemple, en utilisant les cache tags, vous pouvez associer certaines données en cache à un node spécifique. Lorsque ce node est modifié et que son contenu change, les données en cache associées sont invalidées.
Un cache tag est une chaîne de caractères. Par convention, ils sont de la forme thing:identifier et lorsqu'il n'y a pas de concept d'instances multiples d'une chose, il est de la forme simple thing. Il n'y a pas de syntaxe stricte, et la seule règle est : qu'il ne peut pas contenir d'espaces.
Drupal fournit automatiquement les cache tags pour les entités et la configuration - voir la classe de base Entity et la classe de base ConfigBase (tous les types d'entités spécifiques et les objets de configuration héritent de celles-ci).
Les données que Drupal gère se répartissent en 3 catégories de cache tags :
Bien que de nombreux types d'entités suivent un format de cache tags prévisible de <identification du type d'entité>:<identification de l'entité>, le code spécifique que nous développons ne devrait pas s'y fier. Il doit plutôt récupérer les cache tags à invalider pour une seule entité en utilisant sa méthode ::getCacheTags(), par exemple, $node->getCacheTags(), $user->getCacheTags(), etc.
Pour associer des cache tags à un élément de cache nous allons tout simplement fournir un tableau de chaines de caractères ['node:5', 'user:7'].
Selon l'endroit et le contexte d'utilisation cela peut être dans un tableau de rendu :
$userName = \Drupal::currentUser()->getAccountName();
$cacheTags = User::load(\Drupal::currentUser()->id())->getCacheTags();
return [
'#markup' => t('Bonjour @userName !', ['@userName' => $userName]),
'#cache' => [
'tags' => $cacheTags,
]
];
ou en argument d'une méthode set d'un CacheBackend :
$cache_backend->set(
$cid, $data, Cache::PERMANENT, ['node:5', 'user:7']
);
À l’aide du service cache_tags.invalidator à qui l’ont fourni un tableau de chaines de caractères via sa méthode invalidateTags :
\Drupal::service('cache_tags.invalidator')->invalidateTags(['node_list:article']);
Les cache contexts permettent de créer des variations de mises en cache dépendantes du contexte.
Par exemples :
En général, les cache contexts sont issus du contexte de la requête, c'est-à-dire de l'objet Request. La plupart de l'environnement d'une application Web est dérivé du contexte de requête. Après tout, les réponses HTTP sont générées en grande partie en fonction des propriétés des requêtes HTTP qui les ont déclenchées.
Les cache contexts sont hiérarchisés par nature. L'exemple le plus simple à comprendre est le suivant : on fait varier quelque chose par utilisateur, il est inutile de le faire également par permissions. C'est-à-dire l'ensemble des permissions dont dispose un utilisateur, car la variation par utilisateur est déjà plus granulaire.
Un utilisateur a un ensemble de permissions, donc la mise en cache par utilisateur implique la mise en cache par permissions.
Maintenant, si une partie de la page varie en fonction de l'utilisateur et une autre en fonction des permissions, alors Drupal doit être suffisamment intelligent pour que la combinaison des deux : ne varie que par utilisateur. C'est là que Drupal peut exploiter les informations sur la hiérarchie pour ne pas créer de variations inutiles.
Comme les caches tags, les caches contexts sont des chaînes de caractères. Mais contrairement aux caches tags, la syntaxe a ici de la signification :
La liste des cache contexts du core :
cookies
:name
headers
:name
ip
languages
:type
protocol_version
request_format
route
.book_navigation
.menu_active_trails
:menu_name
.name
session
.exists
theme
timezone
url
.path
.is_front
.parent
.query_args
:key
.pagers
:pager_id
.site
user
.is_super_user
.node_grants
:operation
.permissions
.roles
:role
Des exemples concrets :
Il est possible de créer ses propres contextes en définissant des nouveaux services taggués. Les cache contexts sont des services taggués avec 'cache.context', dont les classes implémentent l'interface \Drupal\Core\Cache\Context\CacheContextInterface.
Enfin, les cache contexts ne fonctionnent pas pour les utilisateurs anonymes lorsque le module du cœur Internal Page Cache est activé. S'il est nécessaire d'adopter une stratégie de variation de cache en fonction de contexte, il faut donc le désactiver mais les performances globales en seront impactées.
Le cache max-age fournit un moyen de créer des caches dépendants du temps.
Certaines données ne sont valables que pour une période limitée, et dans ce cas, vous voulez spécifier un âge maximum correspondant.
Cependant, dans le cas du cœur de Drupal, il n'y a pas de données valables que pour une période limitée et les mise en cache sont faites de façon permanente. L'invalidation s’y appuie entièrement sur les cache tags.
Un cache max-age est un nombre entier positif, exprimant un nombre de secondes.
Les durées maximales de cache sont transmises sous forme d'un seul entier, car un élément de cache donné ne peut logiquement avoir qu'une seule durée maximale.
Pour mieux comprendre, voici quelques exemples :
Donc, si vous voulez par exemple empêcher un tableau de rendu d'être mis en cache, vous devez spécifier max-age=0 dessus.
Exemple pour la plupart des tableaux de rendu :
$build['#cache']['max-age'] = 0 ;
Exemple dans une fonction :
\Drupal::cache()->set('my_cache_item', $school_list, \Drupal::time()->getRequestTime() + (86400)) ;
Si vous voulez changer le cache max-age d'un bloc à 0, vous devez implémenter la méthode getCacheMaxAge.
Malheureusement, cache max-age ne fonctionne pas pour les utilisateurs anonymes et le module du cœur de Drupal Internal Page Cache.
Pour terminer, Drupal et notamment la version Drupal 9 propose un système de cache très puissant qui vous permettra d'améliorer les performances de votre site. Pour une maîtrise plus approfondie, n’hésitez pas à consulter la documentation officielle de Drupal.
Pour poursuivre votre lecture, je vous propose cette petite selection :
Crédit photo : monsitj