Nous savons tous que les performances des applications et des sites Web sont un facteur essentiel de leur succès. Cependant, le processus permettant d’améliorer les performances de votre application ou de votre site Web n’est pas toujours clair. La qualité du code et l’infrastructure sont bien sûr essentielles, mais dans de nombreux cas, vous pouvez apporter de vastes améliorations à l’expérience de l’utilisateur final de votre application en vous concentrant sur certaines techniques de livraison d’applications très basiques. Un tel exemple consiste à implémenter et à optimiser la mise en cache dans votre pile d’applications. Cet article de blog couvre les techniques qui peuvent aider les utilisateurs novices et avancés à obtenir de meilleures performances en utilisant les fonctionnalités de cache de contenu incluses dans NGINX et NGINX Plus.
Un cache de contenu se trouve entre un client et un « serveur d’origine » et enregistre des copies de tout le contenu qu’il voit. Si un client demande du contenu que le cache a stocké, il renvoie le contenu directement sans contacter le serveur d'origine. Cela améliore les performances car le cache de contenu est plus proche du client et utilise plus efficacement les serveurs d’applications car ils n’ont pas à effectuer le travail de génération de pages à partir de zéro à chaque fois.
Il existe potentiellement 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) et l’équilibreur de charge ou le proxy inverse situé devant les serveurs d’applications. La mise en cache, même au niveau du proxy inverse/équilibreur de charge, peut considérablement améliorer les performances.
À titre d’exemple, l’année dernière, j’ai entrepris de régler les performances d’un site Web qui se chargeait lentement. L’une des premières choses que j’ai remarquées est qu’il fallait plus d’une seconde pour générer la page d’accueil principale. Après quelques débogages, j'ai découvert que, comme la page était marquée comme non cachable, elle était générée dynamiquement en réponse à chaque requête. La page elle-même ne changeait pas très souvent et n'était pas personnalisée, donc ce n'était pas nécessaire. À titre d’expérience, j’ai marqué la page d’accueil pour qu’elle soit mise en cache pendant 5 secondes par l’équilibreur de charge, et le simple fait de le faire a entraîné une amélioration notable. Le temps d’accès au premier octet est descendu à quelques millisecondes et la page s’est chargée visiblement plus rapidement.
NGINX est généralement déployé en tant que proxy inverse ou équilibreur de charge dans une pile d'applications et dispose d'un ensemble complet de fonctionnalités de mise en cache. La section suivante explique comment configurer la mise en cache de base avec NGINX.
Seules deux directives 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, et la directive proxy_cache
l'active.
proxy_cache_path /chemin/vers/cache niveaux=1:2 clés_zone=mon_cache:10m taille_max=10g inactif=60m use_temp_path=désactivé; serveur { # ... emplacement / { proxy_cache mon_cache; proxy_pass http://mon_stream; } }
Les paramètres de la directive proxy_cache_path
définissent les paramètres suivants :
levels
établit une hiérarchie de répertoires à deux niveaux sous /path/to/cache/ . Avoir un grand nombre de fichiers dans un seul 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 niveaux
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 de cache et les métadonnées telles que les minuteurs d'utilisation. Avoir 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 à aller sur le disque, ce qui accélère considérablement la vérification. Une zone de 1 Mo peut stocker des données pour environ 8 000 clés, donc la zone de 10 Mo configurée dans l'exemple peut stocker des données pour environ 80 000 clés.max_size
définit la limite supérieure de la taille du cache (à 10 gigaoctets dans cet exemple). C'est facultatif ; ne pas spécifier de valeur permet au cache de croître pour utiliser tout l'espace disque disponible. Lorsque la taille du cache atteint la limite, un processus appelé gestionnaire de cache supprime les fichiers les moins récemment utilisés pour ramener la taille du cache sous la limite.inactif
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é depuis 60 minutes est automatiquement supprimé du cache par le processus du gestionnaire de 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é comme défini par un en-tête de contrôle de cache ( Cache-Control:max-age=120
par exemple). Le contenu expiré (obsolète) est supprimé uniquement 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 à partir du serveur d'origine et réinitialise le minuteur d'inactivité
.use_temp_path=off
demande à NGINX de les écrire dans les mêmes répertoires où ils seront mis en cache. Nous vous recommandons de définir ce paramètre sur off
pour éviter la 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 .Et enfin, la directive proxy_cache
active la mise en cache de tout le contenu qui correspond à l'URL du bloc d'emplacement
parent (dans l'exemple, / ). Vous pouvez également inclure la directive proxy_cache
dans un bloc de serveur
; elle s'applique à tous les blocs d'emplacement
du serveur qui n'ont pas leur propre directive proxy_cache
.
Une fonctionnalité puissante de la mise en cache de contenu NGINX est que NGINX peut être configuré pour fournir du contenu obsolète à partir de son cache lorsqu'il ne peut pas obtenir de contenu nouveau à partir des serveurs d'origine. Cela peut se produire si tous les serveurs d'origine d'une ressource mise en cache sont en panne ou temporairement occupés. Plutôt que de relayer l’erreur au client, NGINX fournit la version obsolète du fichier à partir de son cache. Cela fournit un niveau supplémentaire de tolérance aux pannes pour les serveurs proxy NGINX et garantit la disponibilité en cas de pannes de serveur ou de pics de trafic. Pour activer cette fonctionnalité, incluez la directive proxy_cache_use_stale
:
emplacement / { # ... proxy_cache_use_stale erreur délai d'attente http_500 http_502 http_503 http_504; }
Avec cet exemple de configuration, si NGINX reçoit une erreur
, un délai d'attente
ou l'une des erreurs 5xx
spécifiées du serveur d'origine et qu'il dispose d'une version obsolète du fichier demandé dans son cache, il fournit le fichier obsolète au lieu de relayer l'erreur au client.
NGINX dispose d’une multitude de paramètres facultatifs permettant d’affiner 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; serveur { # ... emplacement / { proxy_cache my_cache; proxy_cache_revalidate activé; proxy_cache_min_uses 3; proxy_cache_use_stale erreur timeout mise à jour http_500 http_502 http_503 http_504; proxy_cache_background_update activé; proxy_cache_lock activé; 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 des serveurs d'origine. Si un client demande un élément mis en cache mais expiré comme défini par 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 envoie l'élément complet uniquement s'il a été modifié depuis l'heure enregistrée dans l'en-tête Last-Modified
attaché au fichier lorsque NGINX l'a initialement mis en cache.proxy_cache_min_uses
définit le nombre de fois qu'un élément doit être demandé par les clients avant que NGINX le mette en cache. Cela est utile si le cache se remplit constamment, car cela 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.de mise à jour
de la directive proxy_cache_use_stale
, combiné à l'activation de la directive proxy_cache_background_update
, indique à NGINX de fournir du contenu obsolète lorsque les clients demandent un élément expiré ou en cours de mise à jour à partir du serveur d'origine. Toutes les mises à jour seront effectuées en arrière-plan. Le fichier obsolète est renvoyé pour toutes les demandes jusqu'à ce que le fichier mis à jour soit entièrement téléchargé.proxy_cache_lock
activé, si plusieurs clients demandent un fichier qui n'est pas à jour dans le cache (un MISS
), seule la première de ces demandes est autorisée à accéder au serveur d'origine. Les requêtes restantes attendent que cette requête soit satisfaite, puis extraient le fichier du cache. Sans proxy_cache_lock
activé, toutes les requêtes entraînant des échecs de cache vont directement au serveur d'origine.Si vous disposez de plusieurs disques durs, NGINX peut être utilisé pour répartir le cache entre eux. Voici un exemple qui répartit les clients de manière égale sur deux disques durs en fonction de l'URI de la demande :
proxy_cache_path /chemin/vers/hdd1 niveaux=1:2 zones_clés=mon_cache_hdd1:10m taille_max=10g inactif=60m use_temp_path=désactivé ;
proxy_cache_path /chemin/vers/hdd2 niveaux=1:2 zones_clés=mon_cache_hdd2:10m
taille_max=10g inactif=60m use_temp_path=désactivé ;
split_clients $request_uri $my_cache {
50% « mon_cache_hdd1 » ;
50% « mon_cache_hdd2 » ;
}
serveur {
# ...
emplacement / {
proxy_cache $my_cache ;
proxy_pass http://mon_amont ;
}
}
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
spécifie que les résultats de la moitié des requêtes ( 50%
) sont mis en cache dans my_cache_hdd1
et l'autre moitié dans my_cache_hdd2
. Le hachage basé sur la variable $request_uri
(l'URI de la requête) détermine quel cache est utilisé pour chaque requête, le résultat étant que les requêtes pour un URI donné sont toujours mises en cache dans le même cache.
Veuillez noter que cette approche ne remplace pas une configuration de disque dur RAID. En cas de panne du disque dur, cela peut entraîner un comportement imprévisible du système, notamment l'affichage de codes de réponse 500 pour les demandes dirigées vers le disque dur défaillant. Une configuration de disque dur RAID appropriée peut gérer les pannes de disque dur.
Cette section répond à certaines questions fréquemment posées sur la mise en cache de contenu NGINX.
Oui, avec la directive add_header
:
ajouter_en-tête X-Cache-Status $upstream_cache_status;
Cet exemple ajoute un en-tête HTTP X-Cache-Status
dans les réponses aux clients. Voici les valeurs possibles pour $upstream_cache_status
:
MISS
– La réponse n’a pas été trouvée dans le cache et a donc été récupérée à partir d’un serveur d’origine. La réponse a peut-être alors été mise en cache.BYPASS
– La réponse a été récupérée à partir du serveur d’origine au lieu d’être servie à partir du cache, car la demande correspondait à une directive proxy_cache_bypass
(voir Puis-je percer un trou dans mon cache ? ci-dessous.) La réponse a peut-être alors été mise en cache.EXPIRÉ
– L’entrée dans le cache a expiré. La réponse contient du contenu nouveau provenant du serveur d’origine.STALE
– Le contenu est obsolète car le serveur d’origine ne répond pas correctement et proxy_cache_use_stale
a été configuré.MISE À JOUR
– Le contenu est obsolète car l’entrée est actuellement en cours de mise à jour en réponse à une demande précédente et la mise à jour proxy_cache_use_stale
est configurée.REVALIDATED
– La directive proxy_cache_revalidate
a été activée et NGINX a vérifié que le contenu actuel mis en cache était toujours valide ( If-Modified-Since
ou If-None-Match
).HIT
– La réponse contient du contenu valide et récent provenant directement du cache.NGINX met en cache une réponse uniquement si le serveur d’origine inclut soit l’en-tête Expires
avec une date et une heure dans le futur, soit l’en-tête Cache-Control
avec la directive max-age
définie sur une valeur différente de zéro.
Par défaut, NGINX respecte les autres directives dans l'en-tête Cache-Control
: il ne met pas en cache les réponses lorsque l'en-tête inclut la directive Private
, No-Cache
ou No-Store
. Il ne met pas non plus en cache les réponses avec l'en-tête Set-Cookie
. De plus, il met en cache uniquement les réponses aux requêtes GET
et HEAD
. Vous pouvez remplacer ces valeurs par défaut comme décrit dans les réponses ci-dessous.
NGINX ne met pas en cache les réponses si proxy_buffering
est défini sur off
. Il est activé
par défaut.
de contrôle du cache
peuvent-ils être ignorés ?Oui, avec la directive proxy_ignore_headers
. Par exemple, avec cette configuration :
emplacement /images/ { proxy_cache mon_cache; proxy_ignore_headers Cache-Control; proxy_cache_valid tout 30m; # ... }
NGINX ignore l'en-tête Cache-Control
pour tout ce qui se trouve sous /images/ . La directive proxy_cache_valid
impose une expiration pour les données mises en cache et est requise si 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.
cookie défini
dans l'en-tête ?Oui, avec la directive proxy_ignore_headers
, comme indiqué dans la réponse précédente.
POST
?Oui, avec la directive proxy_cache_methods
:
méthodes_proxy_cache OBTENIR LA PUBLICATION EN TÊTE ;
Cet exemple permet la mise en cache des requêtes POST
.
Oui, à condition que l'en-tête Cache-Control
le permette. La mise en cache de 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 temps d'obtention du premier octet, car la page n'a pas besoin d'être régénérée pour chaque demande.
Oui, avec la directive proxy_cache_bypass
:
emplacement / { proxy_cache_bypass $cookie_nocache $arg_nocache; # ... }
La directive définit les types de requêtes pour lesquels NGINX demande immédiatement du contenu au serveur d'origine au lieu d'essayer de le trouver d'abord dans le cache. C’est ce qu’on appelle parfois « percer un trou » dans la cache. Dans cet exemple, NGINX le fait pour les requêtes avec un cookie ou un argument nocache
, par exemple http://www.example.com/?nocache=true
. NGINX peut toujours mettre en cache la réponse résultante pour les futures demandes qui ne sont pas contournées.
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éel utilisé est légèrement plus compliqué.
proxy_cache_path /chemin/vers/cache niveaux=1:2 clés_zone=mon_cache:10m taille_max=10g inactif=60m use_temp_path=désactivé ;
serveur {
# ...
emplacement / {
proxy_cache mon_cache ;
proxy_pass http://mon_amont ;
}
}
Pour cet exemple de configuration, la clé de cache pour http://www.example.org/my_image.jpg
est calculée comme md5(“http://my_upstream:80/my_image.jpg”)
.
Notez que la variable $proxy_host
est utilisée dans la valeur hachée au lieu du nom d'hôte réel ( www.example.com
). $proxy_host
est défini comme le nom et le port du serveur proxy comme spécifié dans la directive proxy_pass
.
Pour modifier les variables (ou autres termes) utilisées comme base pour la clé, utilisez la directive proxy_cache_key
(voir également la question suivante).
Oui, la clé de cache peut être configurée pour être n'importe quelle valeur arbitraire, par exemple :
clé_cache_proxy $proxy_host $request_uri $cookie_jessionid;
Cet exemple intègre la valeur du cookie JSESSIONID
dans la clé de cache. Les éléments avec le même URI mais des valeurs JSESSIONID
différentes sont mis en cache séparément en tant qu'éléments uniques.
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 avec If-None-Match
.
Si le fichier est à jour dans le cache, NGINX honore une demande de plage d’octets et fournit uniquement les octets spécifiés de l’élément au client. Si le fichier n’est pas mis en cache ou s’il est obsolète, NGINX télécharge l’intégralité du fichier à partir du serveur d’origine. Si la demande concerne une plage d'octets unique, NGINX envoie cette plage au client dès qu'elle est rencontrée dans le flux de téléchargement. Si la demande spécifie plusieurs plages d'octets dans le même fichier, NGINX fournit le fichier entier au client une fois le téléchargement terminé.
Une fois le téléchargement terminé, NGINX déplace l’intégralité de la ressource dans le cache afin que toutes les futures demandes de plage d’octets, qu’il s’agisse d’une plage unique ou de plusieurs plages, soient satisfaites immédiatement à partir du cache.
Veuillez noter que le serveur en amont
doit prendre en charge les demandes de plage d'octets pour que NGINX honore les demandes de plage d'octets adressées à ce serveur en amont
.
NGINX Plus prend en charge la purge sélective des fichiers mis en cache. Ceci est utile si un fichier a été mis à jour sur le serveur d'origine mais est toujours valide dans le cache NGINX Plus (le Cache-Control:max-age
est toujours valide et le délai d'expiration défini par le paramètre inactive
de la directive proxy_cache_path
n'a pas expiré). Avec la fonction de purge du cache de NGINX Plus, ce fichier peut être facilement supprimé. Pour plus de détails, voir Purge du contenu du cache .
Pragma
?L'en-tête Pragma:no-cache
est ajouté par les clients pour contourner tous les caches intermédiaires et accéder directement au serveur d'origine pour le contenu demandé. NGINX ne respecte pas l'en-tête Pragma
par défaut, mais vous pouvez configurer la fonctionnalité avec la directive proxy_cache_bypass
suivante :
emplacement /images/ { proxy_cache mon_cache; proxy_cache_bypass $http_pragma; # ... }
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. À quoi servent ces extensions :
stale-while-revalidate
de l'en-tête HTTP Cache-Control
permet d'utiliser une réponse mise en cache obsolète si elle est en cours de mise à jour.stale-if-error
de l'en-tête HTTP Cache-Control
permet d'utiliser une réponse mise en cache obsolète en cas d'erreur.Ces en-têtes ont une priorité inférieure à la directive proxy_cache_use_stale
décrite ci-dessus.
Vary
?Oui, dans NGINX Plus R5 et NGINX 1.7.7 et versions ultérieures. Voici un bon aperçu de l'en-tête Vary
.
Il existe de nombreuses autres façons de personnaliser et d’ajuster la mise en cache NGINX. Pour en savoir plus sur la mise en cache avec NGINX, veuillez consulter les ressources suivantes :
« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."