Efficience IT
·Formation

Tout savoir sur la mise en cache

Par Louis-Arnaud Catoire

Pourquoi la mise en cache est incontournable

Chaque requête HTTP non mise en cache impose un aller-retour complet entre le client et le serveur : résolution DNS, négociation TLS, traitement applicatif, lecture en base de données, sérialisation de la réponse. Sur une application qui traite plusieurs milliers de requêtes par seconde, chacune de ces étapes représente un coût cumulé considérable en latence, en consommation CPU et en bande passante.

La mise en cache consiste à stocker temporairement le résultat d'un traitement coûteux afin de le restituer directement lors des requêtes suivantes, sans recalcul ni retransmission. Qu'il s'agisse du cache navigateur, d'un proxy intermédiaire ou d'un CDN, le principe fondamental reste identique : servir une copie locale plutôt que solliciter l'origine. Un site correctement configuré peut diviser ses temps de réponse par deux, voire davantage, tout en réduisant significativement la charge sur son infrastructure.

Les couches de cache dans une architecture web

Le cache navigateur

Le navigateur constitue la première couche de mise en cache. Il stocke localement les ressources statiques (images, feuilles de style, scripts JavaScript) associées à leur URL. Lors d'une visite ultérieure, il vérifie en quelques millisecondes si la ressource est déjà disponible localement avant d'émettre une requête réseau. Cette mécanique explique la rapidité de chargement lors du retour en arrière ou de la revisite d'une page. La capacité du cache navigateur, généralement limitée à quelques centaines de mégaoctets, est gérée par un algorithme LRU (Least Recently Used) qui évicte automatiquement les entrées les plus anciennes.

Le cache proxy et le reverse proxy

Les caches proxy, déployés au sein des réseaux d'entreprise ou chez les fournisseurs d'accès, sont des caches partagés qui bénéficient à l'ensemble des utilisateurs d'un même réseau. Un proxy bien dimensionné réduit la bande passante consommée de 30 à 50 %.

Le reverse proxy se positionne côté serveur, devant l'application. Varnish est la référence open source dans ce domaine. Placé en frontal, il intercepte les requêtes entrantes et sert les réponses depuis sa mémoire sans solliciter le serveur applicatif. Varnish utilise le langage VCL (Varnish Configuration Language) pour définir des règles de cache granulaires : durées de vie différenciées par type de contenu, gestion des cookies, traitement des en-têtes Vary. Sur une application Symfony, il est courant de combiner le composant HttpCache intégré au framework avec un Varnish en production pour obtenir des temps de réponse inférieurs à la milliseconde sur les pages publiques.

Les CDN et caches passerelle

Les réseaux de diffusion de contenu (CDN) distribuent des caches passerelle à travers le monde. Cloudflare, Fastly, Akamai ou encore CloudFront placent des copies du contenu sur des serveurs géographiquement proches des utilisateurs finaux. Un visiteur situé à Paris accède au point de présence européen plutôt qu'au serveur d'origine hébergé outre-Atlantique, gagnant plusieurs dizaines de millisecondes par requête. Les CDN modernes vont au-delà du simple cache statique : ils proposent des fonctionnalités de edge computing, de transformation d'images à la volée et de purge instantanée via API.

Le protocole HTTP au service du cache

Expiration : Cache-Control et Expires

L'en-tête Cache-Control, introduit par HTTP 1.1, offre un contrôle précis sur le comportement du cache grâce à ses directives :

  • max-age : durée de fraîcheur en secondes
  • s-maxage : durée applicable uniquement aux caches partagés (proxy, CDN)
  • public : autorise la mise en cache des réponses authentifiées
  • no-cache : oblige la revalidation auprès du serveur avant chaque utilisation
  • no-store : interdit tout stockage de la réponse
  • must-revalidate : impose le respect strict des durées de fraîcheur
  • immutable : signale que la ressource ne changera jamais durant sa durée de vie

L'ancien en-tête Expires, basé sur une date absolue au format HTTP, souffre d'un défaut structurel : il exige la synchronisation des horloges entre client et serveur. Cache-Control, fondé sur des durées relatives, lui est systématiquement préféré.

En pratique, une ressource statique versionnée (par exemple style.a3f5c2.css) reçoit un max-age d'un an couplé à immutable, tandis qu'une page HTML dynamique utilise no-cache pour garantir la revalidation systématique.

Validation : ETag et Last-Modified

Lorsqu'une ressource arrive à expiration, le cache n'a pas nécessairement besoin de la retélécharger intégralement. Le mécanisme de validation conditionnelle permet de vérifier si le contenu a changé sans transférer le corps de la réponse.

L'en-tête Last-Modified indique la date de dernière modification. Lors de la revalidation, le cache envoie une requête conditionnelle avec If-Modified-Since. Si la ressource est inchangée, le serveur répond par un code 304 (Not Modified), économisant bande passante et temps de traitement.

L'ETag (Entity Tag), introduit par HTTP 1.1, fournit un identifiant unique généré à chaque modification de la ressource. Il est vérifié via l'en-tête If-None-Match. L'ETag se révèle indispensable lorsque la granularité temporelle de Last-Modified est insuffisante, par exemple quand un fichier est modifié plusieurs fois dans la même seconde.

Stratégies d'invalidation du cache

Phil Karlton a formulé ce qui reste l'un des aphorismes les plus justes de l'informatique : les deux problèmes difficiles sont le nommage et l'invalidation de cache. L'enjeu est de garantir que les utilisateurs reçoivent toujours la version la plus récente d'une ressource, sans pour autant sacrifier les bénéfices de la mise en cache.

Cache-busting par versioning

L'approche la plus fiable consiste à inclure un hash du contenu dans le nom du fichier. Webpack, Vite et la plupart des outils de build modernes génèrent automatiquement des noms de fichiers versionnés. Quand le contenu change, le nom change, et le navigateur traite la ressource comme entièrement nouvelle. Cette technique permet d'appliquer des durées de cache très longues sans risque d'incohérence.

Purge et ban via API

Les CDN et les reverse proxies exposent des API de purge qui permettent d'invalider une ou plusieurs entrées de cache de manière ciblée. Varnish implémente un mécanisme de ban particulièrement puissant : plutôt que de supprimer physiquement les entrées, il les marque comme invalides via des expressions régulières sur les URL ou les en-têtes, permettant une invalidation massive en une seule opération.

Edge Side Includes (ESI)

ESI permet de composer une page à partir de fragments indépendants, chacun ayant sa propre politique de cache. Le bandeau de navigation, mis à jour une fois par jour, peut être mis en cache pendant 24 heures, tandis que le contenu principal est revalidé à chaque requête. Symfony supporte nativement ESI via son composant HttpCache, et Varnish l'implémente de manière transparente. Cette granularité est essentielle pour les applications où certaines parties de la page sont personnalisées et d'autres sont communes à tous les utilisateurs.

Cohérence du cache en architecture distribuée

Dans une architecture composée de plusieurs serveurs applicatifs, d'un reverse proxy, d'un CDN et éventuellement de caches applicatifs (Redis, Memcached), la cohérence du cache devient un défi architectural majeur.

Le problème du cache stampede

Lorsqu'une entrée de cache populaire expire simultanément pour un grand nombre d'utilisateurs, toutes les requêtes sont redirigées vers le serveur d'origine au même instant. Ce phénomène, appelé cache stampede (ou thundering herd), peut provoquer une surcharge brutale, voire un effondrement du service.

Plusieurs stratégies permettent de s'en prémunir. Le verrouillage probabiliste (probabilistic early expiration) consiste à renouveler le cache de manière anticipée avec une probabilité croissante à mesure que l'expiration approche, répartissant ainsi les régénérations dans le temps. Le mécanisme de lock empêche les requêtes concurrentes de recalculer la même entrée : la première requête verrouille la clé, recalcule la valeur, puis libère le verrou, tandis que les requêtes suivantes attendent ou servent la version périmée (stale-while-revalidate).

Invalidation en cascade et cohérence

Dans un système distribué, invalider une entrée de cache n'est pas une opération atomique. Un changement en base de données doit se propager au cache applicatif, puis au reverse proxy, puis au CDN. Chaque étape introduit un délai pendant lequel différentes couches servent des versions potentiellement incohérentes.

Pour maîtriser cette propagation, il est recommandé d'adopter un modèle événementiel : chaque mutation publie un événement qui déclenche l'invalidation à chaque couche, permettant une propagation ordonnée et traçable. Symfony Messenger, combiné à un bus de messages asynchrone, constitue un excellent support pour implémenter ce patron.

Stale-while-revalidate et stale-if-error

Ces deux directives de Cache-Control offrent un mécanisme de résilience indispensable en production. stale-while-revalidate autorise le cache à servir une réponse périmée pendant qu'il revalide en arrière-plan, garantissant un temps de réponse constant pour l'utilisateur. stale-if-error permet de continuer à servir le contenu en cache lorsque le serveur d'origine est indisponible, transformant le cache en filet de sécurité contre les pannes.

Monitoring et observabilité du cache

Un cache non observé est un cache potentiellement contre-productif. Le taux de hit (proportion de requêtes servies par le cache) est la métrique fondamentale : en dessous de 80 %, la configuration mérite investigation. Les métriques à surveiller incluent également le taux d'éviction, la latence P99, le temps de régénération des entrées et le ratio de réponses stale servies.

Varnish expose ses statistiques via varnishstat, et les CDN fournissent des tableaux de bord détaillés. L'ajout de l'en-tête X-Cache (HIT, MISS, STALE) dans les réponses permet de diagnostiquer le comportement du cache directement depuis les outils de développement du navigateur. En production, l'intégration de ces métriques dans un outil de monitoring comme Prometheus ou Datadog permet de détecter les régressions de performance et d'anticiper les problèmes de capacité.

Pour aller plus loin