Guide de la mise en cache avec NGINX et NGINX Plus

NGINX | 23 juillet 2015

Nous savons tous que les performances des applications et des sites web sont un facteur déterminant de leur réussite. Cependant, la marche à suivre pour améliorer les performances de votre application ou de votre site web n’est pas toujours évidente. La qualité du code et l’infrastructure sont bien sûr essentielles, mais, dans de nombreux cas, vous pouvez considérablement améliorer l’expérience utilisateur de votre application en vous concentrant sur quelques techniques élémentaires de mise à disposition des applications. La mise en œuvre et l’optimisation de la mise en cache dans votre pile applicative en sont un exemple. Cet article de blog présente des techniques qui peuvent aider aussi bien les utilisateurs débutants que confirmés à obtenir de meilleures performances grâce aux fonctionnalités de mise en cache du contenu intégrées à NGINX et NGINX Plus.

Vue d’ensemble

Un cache de contenu se situe entre un client et un « serveur d’origine » et enregistre des copies de tous les contenus qu’il reçoit. Si un client demande un contenu stocké dans le cache, celui-ci le lui renvoie directement sans contacter le serveur d’origine. Cela améliore les performances, car le cache de contenu est plus proche du client, et optimise l’utilisation des serveurs d’applications, qui n’ont ainsi pas à générer les pages de toutes pièces à chaque requête.

Il peut y avoir plusieurs caches entre le navigateur web et le serveur d’applications : le cache du navigateur du client, les caches intermédiaires, les réseaux de diffusion de contenu (CDN), ainsi que l’équilibreur de charge ou le proxy inverse placé devant les serveurs d’applications. La mise en cache, même au niveau du proxy inverse ou de l’équilibreur de charge, peut considérablement améliorer les performances.

À titre d’exemple, l’année dernière, j’ai entrepris d’optimiser les performances d’un site web qui se chargeait lentement. L’une des premières choses que j’ai remarquées était que la génération de la page d’accueil principale prenait plus d’une seconde. Après quelques recherches, j’ai découvert que, la page étant marquée comme ne pouvant pas être mise en cache, elle était générée dynamiquement à chaque requête. Comme son contenu changeait peu souvent et n’était pas personnalisé, cela n’était pas nécessaire. À titre d’essai, j’ai configuré la mise en cache de la page d’accueil pendant 5 secondes par l’équilibreur de charge, et cette seule modification a entraîné une amélioration notable. Le délai avant réception du premier octet est tombé à quelques millisecondes et la page s’est chargée visiblement plus vite.

NGINX est couramment déployé en tant que proxy inverse ou répartiteur de charge dans une pile applicative et offre un ensemble complet de fonctionnalités de mise en cache. La section suivante explique comment configurer une mise en cache de base avec NGINX.

Comment mettre en place et configurer une mise en cache de base

Deux directives seulement sont nécessaires pour activer la mise en cache de base : « proxy_cache_path » et « proxy_cache ». La directive « proxy_cache_path » définit le chemin et la configuration du cache, tandis que la directive « proxy_cache » l’active.

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g                  inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

Les paramètres de la directive « proxy_cache_path » définissent les réglages suivants :

  • Le répertoire du cache sur le disque local est appelé « /path/to/cache/ ».
  • levels configure une hiérarchie de répertoires à deux niveaux sous /path/to/cache/. La présence d’un grand nombre de fichiers dans un même répertoire peut ralentir l’accès aux fichiers. Nous recommandons donc une hiérarchie de répertoires à deux niveaux pour la plupart des déploiements. Si le paramètre levels n’est pas inclus, NGINX place tous les fichiers dans le même répertoire.
  • keys_zone configure une zone de mémoire partagée pour stocker les clés du cache et les métadonnées, telles que les compteurs d’utilisation. Le fait de conserver une copie des clés en mémoire permet à NGINX de déterminer rapidement si une requête est un HIT ou un MISS sans avoir à accéder au disque, ce qui accélère considérablement la vérification. Une zone de 1 Mo peut stocker les données d’environ 8 000 clés ; la zone de 10 Mo configurée dans l’exemple peut donc stocker les données d’environ 80 000 clés.
  • max_size définit la taille maximale du cache (10 gigaoctets dans cet exemple). Ce paramètre est facultatif ; si aucune valeur n’est spécifiée, le cache peut croître jusqu’à utiliser tout l’espace disque disponible. Lorsque la taille du cache atteint cette limite, un processus appelé gestionnaire de cache supprime les fichiers les moins récemment utilisés afin de ramener la taille du cache sous la limite.
  • inactive spécifie combien de temps un élément peut rester dans le cache sans être consulté. Dans cet exemple, un fichier qui n’a pas été demandé pendant 60 minutes est automatiquement supprimé du cache par le processus de gestion du cache, qu’il ait expiré ou non. La valeur par défaut est de 10 minutes (10m). Le contenu inactif diffère du contenu expiré. NGINX ne supprime pas automatiquement le contenu qui a expiré selon les indications d’un en-tête de contrôle du cache (Cache-Control:max-age=120 par exemple). Le contenu expiré (obsolète) n’est supprimé que s’il n’a pas été consulté pendant la durée spécifiée par inactive. Lorsqu’un contenu expiré est consulté, NGINX l’actualise depuis le serveur d’origine et réinitialise le minuteur inactive.
  • NGINX écrit d’abord les fichiers destinés au cache dans une zone de stockage temporaire, et la directive « use_temp_path=off » indique à NGINX de les écrire dans les répertoires où ils seront mis en cache. Nous vous recommandons de définir ce paramètre sur « off » afin d’éviter toute copie inutile de données entre les systèmes de fichiers. « use_temp_path » a été introduit dans NGINX version 1.7.10 et NGINX Plus R6.

Enfin, la directive proxy_cache active la mise en cache de tout le contenu correspondant à l’URL du bloc location parent (dans l’exemple, /). Vous pouvez également inclure la directive proxy_cache dans un bloc server ; elle s’applique à tous les blocs location du serveur qui ne possèdent pas leur propre directive proxy_cache.

Diffusion du contenu mis en cache lorsque le serveur d’origine est indisponible

Une fonctionnalité puissante de la mise en cache de contenu de NGINX permet de configurer NGINX afin qu’il fournisse du contenu obsolète depuis son cache lorsqu’il ne parvient pas à obtenir de contenu à jour auprès des serveurs d’origine. Cela peut se produire si tous les serveurs d’origine d’une ressource mise en cache sont indisponibles ou temporairement surchargés. Au lieu de transmettre l’erreur au client, NGINX fournit la version obsolète du fichier depuis son cache. Cela offre un niveau supplémentaire de tolérance aux pannes pour les serveurs auxquels NGINX sert de proxy et garantit la disponibilité en cas de défaillance des serveurs ou de pics de trafic. Pour activer cette fonctionnalité, incluez la directive proxy_cache_use_stale :

location / {    # ...
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}

Avec cet exemple de configuration, si NGINX reçoit une erreur de type « error », « timeout » ou l’une des erreurs 5xx spécifiées de la part du serveur d’origine et qu’une version obsolète du fichier demandé se trouve dans son cache, il transmet cette version au lieu de renvoyer l’erreur au client.

Optimisation fine du cache et amélioration des performances

NGINX propose de nombreux paramètres facultatifs permettant d’optimiser les performances du cache. Voici un exemple qui en active quelques-uns :

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g                  inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_cache_revalidate on;
        proxy_cache_min_uses 3;
        proxy_cache_use_stale error timeout updating http_500 http_502
                              http_503 http_504;
        proxy_cache_background_update on;
        proxy_cache_lock on;

        proxy_pass http://my_upstream;
    }
}

Ces directives configurent le comportement suivant :

  • proxy_cache_revalidate indique à NGINX d’utiliser des requêtes GET conditionnelles lors de l’actualisation du contenu à partir des serveurs d’origine. Si un client demande un élément mis en cache, mais arrivé à expiration selon les en-têtes de contrôle du cache, NGINX inclut le champ If-Modified-Since dans l’en-tête de la requête GET qu’il envoie au serveur d’origine. Cela permet d’économiser de la bande passante, car le serveur n’envoie l’élément complet que s’il a été modifié depuis la date enregistrée dans l’en-tête Last-Modified associé au fichier lors de sa mise en cache initiale par NGINX.
  • proxy_cache_min_uses définit le nombre de fois qu’un élément doit être demandé par des clients avant que NGINX ne le mette en cache. Cette directive est utile si le cache se remplit constamment, car elle garantit que seuls les éléments les plus fréquemment consultés sont ajoutés au cache. Par défaut, proxy_cache_min_uses est défini sur 1.
  • Le paramètre updating de la directive proxy_cache_use_stale, associé à l’activation de la directive proxy_cache_background_update, indique à NGINX de fournir du contenu obsolète lorsque les clients demandent un élément qui a expiré ou qui est en cours de mise à jour depuis le serveur d’origine. Toutes les mises à jour sont effectuées en arrière-plan. Le fichier obsolète est renvoyé pour toutes les requêtes jusqu’à ce que le fichier mis à jour soit entièrement téléchargé.
  • Lorsque proxy_cache_lock est activé, si plusieurs clients demandent un fichier qui n’est pas à jour dans le cache (un MISS), seule la première de ces requêtes est transmise au serveur d’origine. Les autres requêtes attendent que celle-ci soit satisfaite, puis récupèrent le fichier dans le cache. Lorsque proxy_cache_lock n’est pas activé, toutes les requêtes entraînant un défaut de cache sont directement transmises au serveur d’origine.

Répartition du cache sur plusieurs disques durs

Si vous disposez de plusieurs disques durs, NGINX peut répartir le cache entre eux. Voici un exemple qui répartit uniformément les clients entre deux disques durs en fonction de l’URI de la requête :

proxy_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m                 max_size=10g inactive=60m use_temp_path=off;
proxy_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m
                 max_size=10g inactive=60m use_temp_path=off;

split_clients $request_uri $my_cache {
              50%          “my_cache_hdd1”;
              50%          “my_cache_hdd2”;
}

server {
    # ...
    location / {
        proxy_cache $my_cache;
        proxy_pass http://my_upstream;
    }
}

Les deux directives proxy_cache_path définissent deux caches (my_cache_hdd1 et my_cache_hdd2) sur deux disques durs différents. Le bloc de configuration split_clients indique que les résultats de la moitié des requêtes (50%) sont mis en cache dans my_cache_hdd1 et ceux de l’autre moitié dans my_cache_hdd2. Le hachage basé sur la variable $request_uri (l’URI de la requête) détermine le cache utilisé pour chaque requête. Ainsi, les requêtes correspondant à une URI donnée sont toujours mises en cache dans le même cache.

Veuillez noter que cette approche ne remplace pas une configuration de disques durs en RAID. La défaillance d’un disque dur pourrait entraîner un comportement imprévisible du système, notamment l’affichage de codes de réponse 500 pour les requêtes dirigées vers le disque dur défaillant. Une configuration RAID appropriée permet de gérer les défaillances de disques durs.

Foire aux questions (FAQ)

Cette section répond à certaines questions fréquemment posées sur la mise en cache de contenu avec NGINX.

Peut-on instrumenter le cache NGINX ?

Oui, avec la directive « add_header » :

add_header X-Cache-Status $upstream_cache_status;

Cet exemple ajoute un en-tête HTTP X-Cache-Status aux réponses envoyées aux clients. Les valeurs possibles pour $upstream_cache_status sont les suivantes :

  • MISS – La réponse n’a pas été trouvée dans le cache et a donc été récupérée auprès d’un serveur d’origine. Elle a ensuite éventuellement été mise en cache.
  • BYPASS – La réponse a été récupérée auprès du serveur d’origine au lieu d’être servie depuis le cache, car la requête correspondait à une directive proxy_cache_bypass (voir « Puis-je créer une exception dans mon cache ? » ci-dessous). La réponse a ensuite éventuellement été mise en cache.
  • EXPIRÉE – L’entrée dans le cache a expiré. La réponse contient du contenu actualisé provenant du serveur d’origine.
  • STALE – Le contenu est obsolète, car le serveur d’origine ne répond pas correctement et l’option « proxy_cache_use_stale » a été configurée.
  • UPDATING – Le contenu est obsolète, car l’entrée est en cours de mise à jour en réponse à une requête précédente et l’option « proxy_cache_use_stale updating » est configurée.
  • REVALIDATED – La directive proxy_cache_revalidate était activée et NGINX a vérifié que le contenu actuellement en cache était toujours valide (If-Modified-Since ou If-None-Match).
  • HIT – La réponse contient un contenu valide et à jour provenant directement du cache.

Comment NGINX détermine-t-il s’il doit ou non mettre un élément en cache ?

NGINX ne met en cache une réponse que si le serveur d’origine inclut soit l’en-tête « Expires » avec une date et une heure futures, soit l’en-tête « Cache-Control » avec la directive « max-age » définie sur une valeur non nulle.

Par défaut, NGINX respecte les autres directives de l’en-tête Cache-Control : il ne met pas en cache les réponses lorsque l’en-tête contient la directive Private, No-Cache ou No-Store. Il ne met pas non plus en cache les réponses comportant l’en-tête Set-Cookie. En outre, il met uniquement en cache les réponses aux requêtes GET et HEAD. Vous pouvez modifier ces comportements par défaut comme indiqué dans les réponses ci-dessous.

NGINX ne met pas les réponses en cache si « proxy_buffering » est défini sur « off ». Par défaut, il est défini sur « on .

Peut-on ignorer les en-têtes « Cache-Control » ?

Oui, avec la directive « proxy_ignore_headers ». Par exemple, avec cette configuration :

location /images/ {
    proxy_cache my_cache;
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30m;
    # ...
}

NGINX ignore l’en-tête « Cache-Control » pour tout ce qui se trouve sous /images/. La directive « proxy_cache_valid » impose une date d’expiration aux données mises en cache et est requise lorsque les en-têtes « Cache-Control » sont ignorés. NGINX ne met pas en cache les fichiers qui n’ont pas de date d’expiration.

NGINX peut-il mettre en cache du contenu avec un en-tête « Set-Cookie » ?

Oui, avec la directive « proxy_ignore_headers », comme indiqué dans la réponse précédente.

NGINX peut-il mettre en cache les requêtes « POST » ?

Oui, avec la directive « proxy_cache_methods » :

proxy_cache_methods GET HEAD POST;

Cet exemple permet la mise en cache des requêtes « POST ».

NGINX peut-il mettre en cache du contenu dynamique ?

Oui, à condition que l’en-tête « Cache-Control » l’autorise. La mise en cache du contenu dynamique, même pendant une courte période, peut réduire la charge sur les serveurs d’origine et les bases de données, ce qui améliore le délai avant le premier octet, puisque la page n’a pas besoin d’être régénérée à chaque requête.

Puis-je contourner mon cache de manière sélective ?

Oui, avec la directive « proxy_cache_bypass » :

location / {
    proxy_cache_bypass $cookie_nocache $arg_nocache;
    # ...
}

La directive définit les types de requêtes pour lesquels NGINX demande immédiatement le contenu au serveur d’origine au lieu d’essayer d’abord de le trouver dans le cache. Cette opération est parfois appelée « percer un trou » dans le cache. Dans cet exemple, NGINX le fait pour les requêtes comportant un cookie ou un argument nocache, par exemple http://www.example.com/?nocache=true. NGINX peut tout de même mettre en cache la réponse obtenue pour les futures requêtes qui ne contournent pas le cache.

Quelle clé de cache NGINX utilise-t-il ?

La forme par défaut des clés générées par NGINX est similaire à un hachage MD5 des variables NGINX suivantes : $scheme$proxy_host$request_uri ; l’algorithme réellement utilisé est légèrement plus complexe.

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g                 inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

Pour cet exemple de configuration, la clé de cache pour http://www.example.org/my_image.jpg est calculée comme suit : md5(“http://my_upstream:80/my_image.jpg”).

Notez que la variable « $proxy_host » est utilisée dans la valeur hachée à la place du nom d’hôte réel (www.example.com). La variable « $proxy_host » correspond au nom et au port du serveur mandataire, tels qu’ils sont spécifiés dans la directive « proxy_pass ».

Pour modifier les variables (ou d’autres éléments) servant de base à la clé, utilisez la directive « proxy_cache_key » (voir également la question suivante).

Puis-je utiliser un cookie dans ma clé de cache ?

Oui, la clé de cache peut être configurée avec n’importe quelle valeur, par exemple :

proxy_cache_key $proxy_host$request_uri$cookie_jessionid;

Cet exemple intègre la valeur du cookie « JSESSIONID » dans la clé de cache. Les éléments ayant le même URI, mais des valeurs « JSESSIONID » différentes, sont mis en cache séparément en tant qu’éléments uniques.

NGINX utilise-t-il l’en-tête « ETag » ?

Dans NGINX 1.7.3 et NGINX Plus R5 et versions ultérieures, l’en-tête ETag est entièrement pris en charge, tout comme If-None-Match.

Comment NGINX gère-t-il les requêtes de plages d’octets ?

Si le fichier présent dans le cache est à jour, NGINX traite la requête de plage d’octets et ne transmet au client que les octets spécifiés de l’élément. Si le fichier n’est pas en cache ou s’il est obsolète, NGINX télécharge l’intégralité du fichier depuis le serveur d’origine. Si la requête porte sur une seule plage d’octets, NGINX l’envoie au client dès qu’elle apparaît dans le flux de téléchargement. Si la requête spécifie plusieurs plages d’octets au sein d’un même fichier, NGINX transmet l’intégralité du fichier au client une fois le téléchargement terminé.

Une fois le téléchargement terminé, NGINX place l’intégralité de la ressource dans le cache afin que toutes les futures requêtes de plages d’octets, qu’elles portent sur une seule plage ou sur plusieurs, soient immédiatement satisfaites à partir du cache.

Veuillez noter que le serveur upstream doit prendre en charge les requêtes de plages d’octets pour que NGINX puisse honorer les requêtes de plages d’octets adressées à ce serveur upstream.

NGINX prend-il en charge la purge du cache ?

NGINX Plus prend en charge la purge sélective des fichiers mis en cache. Cette fonctionnalité est utile lorsqu’un fichier a été mis à jour sur le serveur d’origine, mais qu’il est toujours valide dans le cache de NGINX Plus (la valeur de Cache-Control:max-age est toujours valide et le délai défini par le paramètre inactive de la directive proxy_cache_path n’a pas expiré). Grâce à la fonctionnalité de purge du cache de NGINX Plus, ce fichier peut être facilement supprimé. Pour plus de détails, consultez Purge du contenu du cache.

Comment NGINX gère-t-il l’en-tête « Pragma » ?

L’en-tête « Pragma:no-cache » est ajouté par les clients afin de contourner tous les caches intermédiaires et d’accéder directement au serveur d’origine pour obtenir le contenu demandé. Par défaut, NGINX ne tient pas compte de l’en-tête « Pragma », mais vous pouvez configurer cette fonctionnalité à l’aide de la directive « proxy_cache_bypass » suivante :

location /images/ {
    proxy_cache my_cache;
    proxy_cache_bypass $http_pragma;
    # ...
}

NGINX prend-il en charge les extensions « stale-while-revalidate » et « stale-if-error » de l’en-tête « Cache-Control » ?

Oui, dans NGINX Plus R12 et NGINX 1.11.10 et versions ultérieures. Voici ce que font ces extensions :

  • L’extension stale-while-revalidate de l’en-tête HTTP Cache-Control permet d’utiliser une réponse obsolète mise en cache si celle-ci est en cours de mise à jour.
  • L’extension stale-if-error de l’en-tête HTTP Cache-Control permet d’utiliser une réponse obsolète mise en cache en cas d’erreur.

Ces en-têtes ont une priorité inférieure à celle de la directive « proxy_cache_use_stale » décrite ci-dessus.

NGINX prend-il en charge l’en-tête « Vary » ?

Oui, dans NGINX Plus R5 et NGINX 1.7.7 et versions ultérieures. Voici une bonne présentation de l’en-tête Vary header.

Pour aller plus loin

Il existe de nombreuses autres façons de personnaliser et d’optimiser la mise en cache de NGINX. Pour en savoir plus sur la mise en cache avec NGINX, consultez les ressources suivantes :


Partager

À propos de l’auteur

Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
NGINX | 13/10/2025

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA

Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.

Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
NGINX | 03/11/2023

Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?

Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.

Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
NGINX | 11/03/2020

Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX

Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
NGINX | 11/06/2019

Un testeur d’expressions régulières pour NGINX et NGINX Plus

Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.

Caches partagés avec les clusters de cache NGINX Plus, partie 1
NGINX | 24/01/2017

Caches partagés avec les clusters de cache NGINX Plus, partie 1

Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.

Introduction aux microservices
NGINX | 19/05/2015

Introduction aux microservices

Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.