Mise en cache en chaîne
Vue d’ensemble
Flux de données
La diffusion d’une page d’un serveur vers le navigateur d’un client ou d’une cliente traverse une multitude de systèmes et de sous-systèmes. Si vous regardez attentivement, il existe un certain nombre de données de sauts à transférer de la source vers le drain, chacune d’elles étant un candidat potentiel pour la mise en cache.
Flux de données d’une application CMS standard.
Commençons notre parcours avec une donnée qui se trouve sur un disque dur et qui doit être affichée dans un navigateur.
Matériel et système d’exploitation
Tout d’abord, le disque dur (HDD) lui-même dispose d’un cache intégré dans le matériel. Deuxièmement, le système d’exploitation qui monte le disque dur utilise la mémoire libre pour mettre en cache les blocs fréquemment utilisés afin d’accélérer l’accès.
Référentiel de contenu
Le niveau suivant est le CRX ou Oak, la base de données de documents utilisée par AEM. CRX et Oak divisent les données en segments pouvant être mis en cache en mémoire, afin d’éviter un accès plus lent au HDD.
Données tierces
La plupart des grandes installations web disposent également de données tierces ; des données provenant d’un système d’informations sur les produits, un système de gestion des relations client, une base de données héritée ou tout autre service web arbitraire. Ces données n’ont pas besoin d’être extraites de la source à chaque fois que l’on en a besoin, surtout lorsqu’on sait qu’elles changent peu fréquemment. Elles peuvent donc être mises en cache si elles ne sont pas synchronisées dans la base de données CRX.
Couche métier - Application/modèle
En règle générale, vos scripts de modèle n’effectuent pas le rendu du contenu brut provenant de CRX via l’API JCR. Il est probable que vous ayez une couche métier entre les deux qui fusionne, calcule et/ou transforme les données dans un objet de domaine professionnel. Devinez quoi ? Si ces opérations sont coûteuses, envisagez de les mettre en cache.
Fragments de balisage
Le modèle est désormais la base du rendu du balisage d’un composant. Pourquoi ne pas également mettre en cache le modèle rendu ?
Dispatcher, réseau CDN et autres proxys
La page HTML rendue est envoyée au Dispatcher. Nous avons déjà discuté du fait que le principal objectif du Dispatcher est de mettre en cache les pages HTML et d’autres ressources web (malgré son nom). Avant que les ressources n’atteignent le navigateur, il peut transmettre un proxy inverse, qui peut mettre en cache et un réseau CDN, également utilisé pour la mise en cache. Le client ou la cliente peut se trouver dans un bureau qui n’accorde l’accès au web qu’au moyen d’un proxy, et ce proxy peut décider de mettre en cache également pour économiser du trafic.
Mémoire cache du navigateur
Dernier point, mais non des moindres : le navigateur est également mis en cache. Il s’agit d’une ressource que l’on néglige facilement. Mais il s’agit du cache le plus proche et le plus rapide de la chaîne de mise en cache. Malheureusement, il n’est pas partagé entre les utilisateurs et utilisatrices, mais toujours entre différentes demandes d’un utilisateur ou d’une utilisatrice.
Où mettre en cache et pourquoi ?
Il s’agit d’une longue chaîne de mémoires cache potentielles. Et nous avons tous rencontré des problèmes avec des contenus obsolètes. Mais en prenant en compte le nombre d’étapes, c’est un miracle que cela fonctionne la plupart du temps.
Mais à quelle étape de cette chaîne est-il logique de mettre en cache ? Au début ? À la fin ? Tout le temps ? Ça dépend d’un grand nombre de facteurs. Même deux ressources d’un même site web peuvent nécessiter une réponse différente à cette question.
Pour vous donner une idée approximative des facteurs que vous devez prendre en compte :
Durée de vie : si la durée de vie des objets est courte (la durée de vie des données de trafic peut être plus courte que celle des données météorologiques), il peut ne pas être utile de les mettre en cache.
Coût de production : la reproduction et la diffusion d’un objet peuvent être très coûteuses (en termes de cycles de processeur et d’E/S). Si elles ne sont pas très coûteuses, la mise en cache peut ne pas être nécessaire.
Taille : les objets volumineux nécessitent davantage de ressources pour être mis en cache. Cela pourrait être un facteur limitatif et doit être comparé aux avantages.
Fréquence d’accès : si les objets sont rarement accessibles, la mise en cache peut ne pas être efficace. Ils deviennent obsolètes ou sont invalidés avant que l’on y accède la deuxième fois à partir du cache. De tels éléments bloqueraient les ressources de mémoire.
Accès partagé : les données utilisées par plusieurs entités doivent être mises en cache plus haut dans la chaîne. En fait, la chaîne de mise en cache n’est pas une chaîne, mais une arborescence. Une donnée du référentiel peut être utilisée par plusieurs modèles. Ces modèles peuvent à leur tour être utilisés par plusieurs scripts de rendu pour générer des fragments de HTML. Ces fragments sont inclus dans plusieurs pages qui sont distribuées à plusieurs utilisateurs ou utilisatrices avec leurs caches privés dans le navigateur. Donc « partager » ne signifie pas partager seulement entre des personnes, mais plutôt entre des morceaux de logiciels. Si vous souhaitez trouver un cache « partagé » potentiel, remontez simplement l’arborescence vers la racine et recherchez un ancêtre commun, c’est là que vous devez mettre en cache.
Répartition géographique : si vos utilisateurs et utilisatrices sont répartis dans le monde entier, l’utilisation d’un réseau de caches distribué peut contribuer à réduire la latence.
Bande passante réseau et latence : en parlant de latence, qui sont vos clientes et clients et quel type de réseau utilisent-ils ? Peut-être qu’il s’agit de clientes et clients mobiles dans un pays sous-développé qui utilisent la connexion 3G de smartphones de génération plus ancienne ? Envisagez de créer des objets plus petits et de les mettre en cache dans les caches du navigateur.
Cette liste est loin d’être exhaustive, mais nous pensons que vous avez maintenant compris l’idée.
Règles de base pour la mise en cache en chaîne
Encore une fois : la mise en cache est difficile. Partageons quelques règles de base que nous avons extraites de projets précédents qui peuvent vous aider à éviter des problèmes dans votre projet.
Éviter la double mise en cache
Chacune des couches introduites dans le dernier chapitre apporte une certaine valeur dans la chaîne de mise en cache. Soit en économisant les cycles de calcul, soit en rapprochant les données des consommateurs et consommatrices. Ce n’est pas une mauvaise chose de mettre en cache une donnée à plusieurs étapes de la chaîne, mais vous devez toujours tenir compte des avantages et des coûts de la prochaine étape. La mise en cache d’une page entière dans le système de publication n’offre généralement aucun avantage, étant donné qu’elle est déjà faite dans Dispatcher.
Mélanger des stratégies d’invalidation
Il existe trois stratégies d’invalidation de base :
- TTL, Time to Live : un objet expire après un délai fixe (par exemple, « dans 2 heures »).
- Date d’expiration : l’objet expire au moment défini (par exemple, « 17 h 00 le 10 juin 2019 »).
- Basée sur un événement : l’objet est invalidé explicitement par un événement qui s’est produit dans la plateforme (par exemple, lorsqu’une page est modifiée et activée).
Vous pouvez maintenant utiliser différentes stratégies sur différentes couches de cache, mais il y en a des « dangereuses ».
Invalidation basée sur un événement
Invalidation pure basée sur un événement : invalidation du cache interne vers la couche externe
L’invalidation pure basée sur un événement est la plus facile à comprendre, à réaliser en théorie et la plus précise.
En termes simples, les caches sont invalidés un par un après la modification de l’objet.
Vous devez simplement garder une règle à l’esprit :
Invalidez toujours depuis le cache interne vers le cache externe. Si vous avez d’abord invalidé un cache externe, il se peut qu’il remette en cache le contenu obsolète d’un cache interne. Ne faites aucune supposition du moment où un cache est réactualisé ; veillez à ce que le cache soit vraiment réactualisé. Au mieux, en déclenchant l’invalidation du cache externe après celle du cache interne.
Voilà la théorie. Mais en pratique il y a un certain nombre de pièges. Les événements doivent être distribués, potentiellement sur un réseau. En pratique, cela en fait le schéma d’invalidation le plus difficile à mettre en œuvre.
Auto dépannage
Avec l’invalidation basée sur un événement, vous devriez avoir un plan alternatif. Que se passe-t-il si un événement d’invalidation est manqué ? Une stratégie simple peut être d’invalider ou de purger après un certain temps. Vous avez peut-être manqué cet événement et vous avez maintenant diffusé du contenu obsolète. Mais vos objets ont également une durée de vie implicite de plusieurs heures (jours) uniquement. Finalement, le système se dépanne alors automatiquement.
Invalidation pure basée sur TTL
Invalidation basée sur TTL non synchronisée.
C’est aussi un système assez courant. Vous empilez plusieurs couches de caches, chacune ayant le droit de servir un objet pendant un certain temps.
C’est facile à mettre en œuvre. Malheureusement, il est difficile de prédire la durée de vie effective d’une donnée.
Cache externe prolongeant la durée de vie d’un objet interne.
Examinez l’illustration ci-dessus. Chaque couche de mise en cache ajoute une durée de vie (TTL) de 2 minutes. On pourrait alors penser que la durée de vie globale (TTL) doit être également de 2 minutes. Pas tout à fait. Si la couche externe récupère l’objet juste avant qu’il ne soit obsolète, la couche externe prolonge effectivement la durée de vie effective de l’objet. Dans ce cas, la durée de vie effective peut être comprise entre 2 et 4 minutes. Supposons que vous ayez convenu avec votre service commercial qu’une journée est acceptable et que vous disposez de quatre couches de caches. La durée de vie réelle de chaque couche ne doit pas dépasser six heures, ce qui augmente le taux d’absence de cache.
Ce n’est pas forcément un mauvais système. Il convient simplement d’en connaître les limites. Il s’agit d’une stratégie simple et efficace pour commencer. Ce n’est que si le trafic de votre site augmente que vous pouvez envisager une stratégie plus précise.
Synchroniser l’heure d’invalidation en définissant une date spécifique
Invalidation basée sur les dates d’expiration
La durée de vie effective est plus prévisible en définissant une date spécifique sur l’objet interne et en la propageant aux caches externes.
Synchronisation des dates d’expiration.
Cependant, tous les caches ne sont pas en mesure de propager les dates. Et la démarche peut devenir problématique lorsque le cache externe agrège deux objets internes avec des dates d’expiration différentes.
Mélanger des invalidations basées sur les événements et sur la durée de vie
Mélange d’invalidations basées sur les événements et sur la durée de vie.
Un autre système courant dans le monde AEM consiste à utiliser l’invalidation basée sur les événements dans les caches internes (par exemple, les caches en mémoire où les événements peuvent être traités en temps quasi réel) et les caches TTL à l’extérieur, où vous n’avez peut-être pas accès à l’invalidation explicite.
Dans le monde d’AEM, vous disposez d’un cache en mémoire pour les objets commerciaux et les fragments de HTML dans les systèmes de publication, qui est invalidé lorsque les ressources sous-jacentes changent et que vous propagez cet événement de modification au Dispatcher, qui fonctionne également selon les événements. En amont, vous auriez par exemple un réseau CDN basé sur la durée de vie.
Disposer d’une couche de mise en cache basée sur la durée de vie (courte) en amont de Dispatcher pourrait effectivement atténuer un pic qui se produirait généralement après une invalidation automatique.
Mélanger des invalidations basées sur la durée de vie et sur des événements
Dangereux : mélanger des invalidations basées sur la durée de vie et sur des événements
Cette combinaison est dangereuse. Ne placez jamais de cache basé sur un événement après une mise en cache basée sur la durée de vie ou sur l’expiration. Rappelez-vous cet effet de débordement que nous avons eu dans la stratégie « pure-TTL ». Le même effet peut être observé ici. Seulement, l’événement d’invalidation du cache externe qui s’est déjà produit ne se reproduira peut-être plus jamais, ce qui peut prolonger à l’infini la durée de vie de votre objet mis en cache.
Invalidation basée sur TTL et basée sur les événements combinée : débordement infini.
Mise en cache partielle et mise en cache en mémoire
Vous pouvez vous connecter à l’étape du processus de rendu pour ajouter des calques de mise en cache. De l’obtention d’objets de transfert de données distants ou la création d’objets métier locaux à la mise en cache du balisage rendu d’un seul composant. Nous consacrerons un prochain tutoriel aux mises en œuvre concrètes. Mais peut-être avez-vous déjà mis en œuvre vous-même quelques-unes de ces couches de mise en cache. Nous nous devons donc de présenter ici les principes de base, tout comme les pièges.
Quelques avertissements
Respectez le contrôle d’accès.
Les techniques décrites ici sont assez puissantes et sont indispensables dans la boîte à outils de chaque développeur ou développeuse AEM. Mais ne vous enflammez pas, utilisez-les sagement. Le fait de stocker un objet dans un cache et de le partager avec d’autres utilisateurs et utilisatrices dans des demandes de suivi revient à contourner le contrôle d’accès. Ce n’est en général pas un problème sur les sites web publics, mais cela le devient lorsqu’un utilisateur ou une utilisatrice doit se connecter avant d’y accéder.
Imaginez que vous stockiez le balisage HTML d’un menu principal de sites dans un cache en mémoire pour le partager entre différentes pages. Il s’agit en fait d’un exemple parfait pour stocker le HTML partiellement rendu, car la création d’une navigation est généralement coûteuse étant donné qu’elle nécessite de parcourir de nombreuses pages.
Vous ne partagez pas cette même structure de menus entre toutes les pages, mais également avec tous les utilisateurs et toutes les utilisatrices, ce qui la rend encore plus efficace. Mais attendez… il existe peut-être des éléments dans le menu qui ne sont réservés qu’à un certain groupe d’utilisateurs et d’utilisatrices. Dans ce cas, la mise en cache peut devenir un peu plus complexe.