Compréhension de la proxy HTTP Nginx, de l’équilibrage de charge, de la mise en mémoire tampon et de la mise en cache

introduction

Dans ce guide, nous aborderons les fonctionnalités de proxy http de Nginx, qui permettent à Nginx de transmettre des demandes aux serveurs HTTP d’arrière-plan pour un traitement ultérieur. Nginx est souvent configuré en tant que solution de proxy inverse pour aider à faire évoluer l'infrastructure ou pour transmettre des requêtes à d'autres serveurs qui ne sont pas conçus pour gérer des charges client importantes.

En cours de route, nous verrons comment passer à l’extérieur en utilisant les fonctionnalités intégrées d’équilibrage de charge de Nginx. Nous allons également explorer la mise en mémoire tampon et la mise en cache pour améliorer les performances des opérations de proxy pour les clients.

Informations générales sur la procuration

Si vous utilisiez auparavant uniquement des serveurs Web pour des configurations simples à serveur unique, vous vous demandez peut-être pourquoi vous auriez besoin de requêtes proxy.

L'une des raisons pour utiliser un proxy sur d'autres serveurs à partir de Nginx est la possibilité de faire évoluer votre infrastructure. Nginx est conçu pour gérer plusieurs connexions simultanées en même temps. Cela le rend idéal pour être le point de contact des clients. Le serveur peut transmettre des demandes à un nombre quelconque de serveurs dorsaux pour gérer la majeure partie du travail, ce qui répartit la charge sur votre infrastructure. Cette conception vous offre également la possibilité d'ajouter facilement des serveurs d’arrière-plan ou de les supprimer au besoin pour des raisons de maintenance.

Un proxy http peut également s'avérer utile lorsque vous utilisez des serveurs d'applications qui ne sont peut-être pas conçus pour gérer directement les demandes provenant de clients dans des environnements de production. De nombreux frameworks incluent des serveurs Web, mais la plupart d'entre eux ne sont pas aussi robustes que des serveurs conçus pour des performances élevées comme Nginx. Mettre Nginx devant ces serveurs peut améliorer l'expérience des utilisateurs et renforcer la sécurité.

La procuration dans Nginx est réalisée en manipulant une requête adressée au serveur Nginx et en la transmettant à d'autres serveurs pour le traitement effectif. Le résultat de la demande est renvoyé à Nginx, qui relaie ensuite les informations au client. Les autres serveurs de cette instance peuvent être des machines distantes, des serveurs locaux ou même d'autres serveurs virtuels définis dans Nginx. Les serveurs auxquels Nginx proxie les demandes sont appelésupstream servers.

Nginx peut envoyer des requêtes proxy aux serveurs qui communiquent à l'aide des protocoles http (s), FastCGI, SCGI et uwsgi ou memcached, via des ensembles de directives distincts pour chaque type de proxy. Dans ce guide, nous nous concentrerons sur le protocole http. L'instance Nginx est chargée de transmettre la demande et de masser tous les composants du message dans un format que le serveur en amont peut comprendre.

Déconstruire une passe de proxy HTTP de base

Le type de proxy le plus simple consiste à transmettre une requête à un seul serveur capable de communiquer via http. Ce type de proxy est connu sous le nom de «proxy pass» générique et est géré par la directiveproxy_pass bien nommée.

La directiveproxy_pass se trouve principalement dans les contextes de localisation. Il est également valide dans les blocsif dans un contexte de localisation et dans les contexteslimit_except. Lorsqu'une demande correspond à un emplacement avec une directiveproxy_pass à l'intérieur, la demande est transmise à l'URL fournie par la directive.

Prenons un exemple:

# server context

location /match/here {
    proxy_pass http://example.com;
}

. . .

Dans l'extrait de configuration ci-dessus, aucun URI n'est donné à la fin du serveur dans la définition deproxy_pass. Pour les définitions qui correspondent à ce modèle, l'URI demandé par le client sera transmis tel quel au serveur en amont.

Par exemple, lorsqu'une demande pour/match/here/please est gérée par ce bloc, l'URI de la demande sera envoyée au serveurexample.com en tant quehttp://example.com/match/here/please.

Examinons le scénario alternatif:

# server context

location /match/here {
    proxy_pass http://example.com/new/prefix;
}

. . .

Dans l'exemple ci-dessus, le serveur proxy est défini avec un segment URI à la fin (/new/prefix). Lorsqu'un URI est donné dans la définition deproxy_pass, la partie de la requête qui correspond à la définition delocation est remplacée par cet URI lors du passage.

Par exemple, une demande de/match/here/please sur le serveur Nginx sera transmise au serveur en amont en tant quehttp://example.com/new/prefix/please. Le/match/here est remplacé par/new/prefix. C'est un point important à garder à l'esprit.

Parfois, ce type de remplacement est impossible. Dans ces cas, l'URI à la fin de la définition deproxy_pass est ignoré et soit l'URI d'origine du client, soit l'URI tel que modifié par d'autres directives sera passé au serveur en amont.

Par exemple, lorsque l'emplacement correspond à l'aide d'expressions régulières, Nginx ne peut pas déterminer la partie de l'URI qui correspond à l'expression. Il envoie donc l'URI de la demande du client d'origine. Un autre exemple est celui où une directive de réécriture est utilisée au même emplacement, ce qui entraîne la réécriture de l'URI du client, mais elle est toujours traitée dans le même bloc. Dans ce cas, l'URI réécrit sera transmis.

Comprendre comment Nginx traite les en-têtes

Une chose qui peut ne pas être tout de suite claire est qu'il est important de transmettre plus que l'URI si vous vous attendez à ce que le serveur en amont traite correctement la demande. La demande émanant de Nginx pour le compte d'un client sera différente de la demande émanant directement d'un client. Une grande partie de ceci est les en-têtes qui vont avec la demande.

Lorsque Nginx envoie une requête par proxy, il apporte automatiquement des modifications aux en-têtes de requête qu'elle reçoit du client:

  • Nginx se débarrasse de tous les en-têtes vides. Il est inutile de transmettre des valeurs vides à un autre serveur. cela ne ferait que gonfler la demande.

  • Nginx, par défaut, considérera tout en-tête contenant des traits de soulignement comme non valide. Il va les supprimer de la requête mandatée. Si vous souhaitez que Nginx les interprète comme valides, vous pouvez définir la directiveunderscores_in_headers sur «on», sinon vos en-têtes ne parviendront jamais au serveur principal.

  • L'en-tête «Host» est réécrit à la valeur définie par la variable$proxy_host. Ce sera l'adresse IP ou le nom et le numéro de port de l'amont, directement tels que définis par la directiveproxy_pass.

  • L'en-tête «Connection» est remplacé par «close». Cet en-tête est utilisé pour signaler des informations sur la connexion particulière établie entre deux parties. Dans ce cas, Nginx définit ceci sur «close» pour indiquer au serveur en amont que cette connexion sera fermée une fois que la demande initiale aura été traitée. L'amont ne devrait pas s'attendre à ce que cette connexion soit persistante.

Le premier point que nous pouvons extrapoler à partir de ce qui précède est que tout en-tête que vousdo notvoulez passer doit être défini sur une chaîne vide. Les en-têtes avec des valeurs vides sont complètement supprimés de la requête transmise.

Le point suivant à glaner à partir des informations ci-dessus est que si votre application backend traitera des en-têtes non standard, vous devez vous assurer qu'ilsdo not ont des traits de soulignement. Si vous avez besoin d'en-têtes qui utilisent un trait de soulignement, vous pouvez définir la directiveunderscores_in_headers sur «on» plus haut dans votre configuration (valide soit dans le contexte http, soit dans le contexte de la déclaration du serveur par défaut pour l'adresse IP / le port combinaison). Si vous ne le faites pas, Nginx signalera ces en-têtes comme non valides et les supprimera silencieusement avant de les transmettre à votre amont.

L'en-tête "Host" revêt une importance particulière dans la plupart des scénarios de proxy. Comme indiqué ci-dessus, par défaut, ce paramètre sera défini sur la valeur de$proxy_host, une variable qui contiendra le nom de domaine ou l'adresse IP et le port provenant directement de la définition deproxy_pass. Cette option est sélectionnée par défaut car c'est la seule adresse sur laquelle Nginx peut être sûr que le serveur en amont répond (car il est extrait directement des informations de connexion).

Les valeurs les plus courantes pour l'en-tête “Host” sont les suivantes:

  • $proxy_host: Ceci définit l'en-tête «Host» sur le nom de domaine ou l'adresse IP et la combinaison de ports tirée de la définition deproxy_pass. Ceci est la valeur par défaut et "sûre" du point de vue de Nginx, mais ne correspond généralement pas à ce dont le serveur mandaté a besoin pour traiter correctement la demande.

  • $http_host: définit l'en-tête «Host» sur l'en-tête «Host» de la demande du client. Les en-têtes envoyés par le client sont toujours disponibles dans Nginx en tant que variables. Les variables commenceront par un préfixe$http_, suivi du nom de l'en-tête en minuscules, avec tous les tirets remplacés par des traits de soulignement. Bien que la variable$http_host fonctionne la plupart du temps, lorsque la demande du client n'a pas d'en-tête «Host» valide, cela peut entraîner l'échec de la réussite.

  • $host: Cette variable est définie, par ordre de préférence, sur: le nom d'hôte de la ligne de requête elle-même, l'en-tête «Host» de la requête client, ou le nom du serveur correspondant à la requête.

Dans la plupart des cas, vous voudrez définir l'en-tête «Host» sur la variable$host. C'est le plus flexible et fournira généralement aux serveurs mandatés avec un en-tête “Host” rempli le plus précisément possible.

Définition ou réinitialisation des en-têtes

Pour ajuster ou définir des en-têtes pour les connexions proxy, nous pouvons utiliser la directiveproxy_set_header. Par exemple, pour modifier l’en-tête «Host» (hôte) comme nous l’avons vu et ajouter quelques en-têtes supplémentaires communs aux demandes transmises par proxy, nous pourrions utiliser quelque chose comme ceci:

# server context

location /match/here {
    proxy_set_header HOST $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_pass http://example.com/new/prefix;
}

. . .

La demande ci-dessus définit l'en-tête «Host» sur la variable$host, qui doit contenir des informations sur l'hôte d'origine demandé. L'en-têteX-Forwarded-Proto donne les informations du serveur mandaté sur le schéma de la requête client d'origine (qu'il s'agisse d'une requête http ou https).

LeX-Real-IP est défini sur l'adresse IP du client afin que le proxy puisse correctement prendre des décisions ou se connecter en fonction de ces informations. L'en-têteX-Forwarded-For est une liste contenant les adresses IP de chaque serveur par lequel le client a été mandaté jusqu'à ce point. Dans l'exemple ci-dessus, nous définissons ceci sur la variable$proxy_add_x_forwarded_for. Cette variable prend la valeur de l’en-têteX-Forwarded-For d’origine récupéré du client et ajoute l’adresse IP du serveur Nginx à la fin.

Bien sûr, nous pourrions déplacer les directivesproxy_set_header vers le serveur ou le contexte http, ce qui lui permet d'être référencé à plusieurs endroits:

# server context

proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

location /match/here {
    proxy_pass http://example.com/new/prefix;
}

location /different/match {
    proxy_pass http://example.com;
}

Définition d'un contexte amont pour l'équilibrage de charge des connexions par proxy

Dans les exemples précédents, nous avons montré comment créer un proxy http simple sur un serveur dorsal unique. Nginx nous permet d’évoluer facilement cette configuration en spécifiant des pools entiers de serveurs principaux auxquels nous pouvons transmettre des demandes.

Nous pouvons le faire en utilisant la directiveupstream pour définir un pool de serveurs. Cette configuration suppose que l’un des serveurs répertoriés est capable de gérer une demande client. Cela nous permet de déployer notre infrastructure sans presque aucun effort. La directiveupstream doit être définie dans le contexte http de votre configuration Nginx.

Voyons un exemple simple:

# http context

upstream backend_hosts {
    server host1.example.com;
    server host2.example.com;
    server host3.example.com;
}

server {
    listen 80;
    server_name example.com;

    location /proxy-me {
        proxy_pass http://backend_hosts;
    }
}

Dans l'exemple ci-dessus, nous avons configuré un contexte en amont appelébackend_hosts. Une fois défini, ce nom pourra être utilisé dans les passes de proxy comme s'il s'agissait d'un nom de domaine classique. Comme vous pouvez le voir, dans notre bloc serveur, nous transmettons toute demande faite àexample.com/proxy-me/... au pool que nous avons défini ci-dessus. Dans ce pool, un hôte est sélectionné en appliquant un algorithme configurable. Par défaut, il ne s'agit que d'un simple processus de sélection alternatif (chaque demande sera acheminée vers un hôte différent à son tour).

Modification de l'algorithme d'équilibrage en amont

Vous pouvez modifier l'algorithme d'équilibrage utilisé par le pool en amont en incluant des directives ou des indicateurs dans le contexte en amont:

  • (round robin): algorithme d'équilibrage de charge par défaut utilisé si aucune autre directive d'équilibrage n'est présente. Chaque serveur défini dans le contexte en amont se voit transmettre successivement les demandes.

  • least_conn: spécifie que les nouvelles connexions doivent toujours être données au backend qui a le moins de connexions actives. Cela peut être particulièrement utile dans les situations où les connexions au serveur peuvent durer un certain temps.

  • ip_hash: cet algorithme d'équilibrage distribue les demandes à différents serveurs en fonction de l'adresse IP du client. Les trois premiers octets sont utilisés comme clé pour décider sur le serveur qui gérera la demande. Le résultat est que les clients ont tendance à être servis par le même serveur à chaque fois, ce qui peut contribuer à la cohérence de la session.

  • hash: cet algorithme d'équilibrage est principalement utilisé avec le proxy Memcached. Les serveurs sont divisés en fonction de la valeur d'une clé de hachage fournie de manière arbitraire. Cela peut être du texte, des variables ou une combinaison. C’est la seule méthode d’équilibrage qui demande à l’utilisateur de fournir des données, qui constituent la clé à utiliser pour le hachage.

Lors du changement d'algorithme d'équilibrage, le bloc peut ressembler à ceci:

# http context

upstream backend_hosts {

    least_conn;

    server host1.example.com;
    server host2.example.com;
    server host3.example.com;
}

. . .

Dans l'exemple ci-dessus, le serveur sera sélectionné en fonction de celui qui a le moins de connexions. La directiveip_hash pourrait être définie de la même manière pour obtenir une certaine quantité de «stickiness» de session.

Comme pour la méthodehash, vous devez fournir la clé contre laquelle hacher. Cela peut être ce que vous souhaitez:

# http context

upstream backend_hosts {

    hash $remote_addr$remote_port consistent;

    server host1.example.com;
    server host2.example.com;
    server host3.example.com;
}

. . .

L'exemple ci-dessus distribuera les demandes en fonction de la valeur de l'adresse IP et du port du client. Nous avons également ajouté le paramètre optionnelconsistent, qui implémente l'algorithme de hachage cohérent ketama. En gros, cela signifie que si vos serveurs en amont changent, l'impact sur votre cache sera minime.

Définition du poids du serveur pour l'équilibrage

Dans les déclarations des serveurs principaux, par défaut, chaque serveur est également «pondéré». Cela suppose que chaque serveur peut et doit gérer la même charge (en tenant compte des effets des algorithmes d'équilibrage). Toutefois, vous pouvez également définir une pondération alternative pour les serveurs lors de la déclaration:

# http context

upstream backend_hosts {
    server host1.example.com weight=3;
    server host2.example.com;
    server host3.example.com;
}

. . .

Dans l'exemple ci-dessus,host1.example.com recevra trois fois le trafic des deux autres serveurs. Par défaut, un poids de un est attribué à chaque serveur.

Utilisation de tampons pour libérer des serveurs principaux

Un problème lié à la procuration qui préoccupe de nombreux utilisateurs est l’impact sur les performances de l’ajout d’un serveur supplémentaire au processus. Dans la plupart des cas, cela peut être largement atténué en tirant parti des capacités de mise en mémoire tampon et de mise en cache de Nginx.

Lorsqu’un serveur proxy est envoyé à un autre serveur, la vitesse de deux connexions différentes affectera l’expérience du client:

  • La connexion du client au proxy Nginx.

  • La connexion du proxy Nginx au serveur principal.

Nginx a la possibilité d’ajuster son comportement en fonction de l’une de ces connexions que vous souhaitez optimiser.

Sans mémoire tampon, les données sont envoyées par le serveur mandaté et commencent immédiatement à être transmises au client. Si les clients sont supposés être rapides, la mise en mémoire tampon peut être désactivée afin de transférer les données au client dès que possible. Avec les tampons, le proxy Nginx stockera temporairement la réponse du serveur, puis transmettra ces données au client. Si le client est lent, cela permet au serveur Nginx de fermer la connexion au backend plus tôt. Il peut ensuite gérer la distribution des données au client à un rythme aussi rapide que possible.

Nginx utilise par défaut une conception de mise en mémoire tampon, car les clients ont généralement des vitesses de connexion très différentes. Nous pouvons ajuster le comportement de mise en mémoire tampon avec les directives suivantes. Ceux-ci peuvent être définis dans les contextes http, serveur ou emplacement. Il est important de garder à l'esprit que les directives de dimensionnement sont configuréesper request, donc les augmenter au-delà de vos besoins peut affecter vos performances lorsqu'il y a de nombreuses demandes client:

  • proxy_buffering: cette directive contrôle si la mise en mémoire tampon pour ce contexte et les contextes enfants est activée. Par défaut, cette option est activée.

  • proxy_buffers: cette directive contrôle le nombre (premier argument) et la taille (deuxième argument) des tampons pour les réponses mandatées. La valeur par défaut est de configurer 8 tampons d'une taille égale à une page mémoire (soit4k ou8k). L'augmentation du nombre de mémoires tampons peut vous permettre de stocker davantage d'informations en mémoire tampon.

  • proxy_buffer_size: la partie initiale de la réponse d'un serveur principal, qui contient des en-têtes, est mise en mémoire tampon séparément du reste de la réponse. Cette directive définit la taille de la mémoire tampon pour cette partie de la réponse. Par défaut, ce sera la même taille queproxy_buffers, mais comme il est utilisé pour les informations d'en-tête, cela peut généralement être défini sur une valeur inférieure.

  • proxy_busy_buffers_size: Cette directive définit la taille maximale des tampons qui peuvent être marqués «prêts pour le client» et donc occupés. Alors qu'un client ne peut lire les données que d'un seul tampon à la fois, les tampons sont placés dans une file d'attente pour être envoyés au client par groupes. Cette directive contrôle la taille de la mémoire tampon autorisée à se trouver dans cet état.

  • proxy_max_temp_file_size: il s'agit de la taille maximale, par requête, d'un fichier temporaire sur disque. Celles-ci sont créées lorsque la réponse en amont est trop volumineuse pour tenir dans un tampon.

  • proxy_temp_file_write_size: il s'agit de la quantité de données que Nginx écrira dans le fichier temporaire à un moment donné lorsque la réponse du serveur mandaté est trop importante pour les tampons configurés.

  • proxy_temp_path: c'est le chemin vers la zone sur le disque où Nginx doit stocker tous les fichiers temporaires lorsque la réponse du serveur en amont ne peut pas tenir dans les tampons configurés.

Comme vous pouvez le constater, Nginx fournit plusieurs directives différentes permettant d’ajuster le comportement de la mise en mémoire tampon. La plupart du temps, vous n'aurez pas à vous soucier de la majorité d'entre eux, mais il peut être utile d'ajuster certaines de ces valeurs. Les directivesproxy_buffers etproxy_buffer_size sont probablement les plus utiles à ajuster.

Un exemple qui augmente le nombre de mémoires tampon de proxy disponibles pour chaque demande en amont, tandis que la réduction de la mémoire tampon qui stocke probablement les en-têtes ressemblerait à ceci:

# server context

proxy_buffering on;
proxy_buffer_size 1k;
proxy_buffers 24 4k;
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;

location / {
    proxy_pass http://example.com;
}

En revanche, si vous souhaitez servir immédiatement des données sur des clients rapides, vous pouvez désactiver complètement la mise en mémoire tampon. En fait, Nginx utilisera toujours des tampons si le flux amont est plus rapide que le client, mais essaiera immédiatement de vider les données sur le client au lieu d'attendre que le tampon soit mis en pool. Si le client est lent, la connexion en amont peut rester ouverte jusqu'à ce que le client puisse le rattraper. Lorsque la mise en mémoire tampon est désactivée, seul le tampon défini par la directiveproxy_buffer_size sera utilisé:

# server context

proxy_buffering off;
proxy_buffer_size 4k;

location / {
    proxy_pass http://example.com;
}

Haute disponibilité (facultatif)

Nginx proxy peut être rendu plus robuste en ajoutant un ensemble redondant d'équilibreurs de charge, créant une infrastructure à haute disponibilité.

Une configurationhigh availability (HA) est une infrastructure sans point de défaillance unique, et vos équilibreurs de charge font partie de cette configuration. En disposant de plusieurs équilibreurs de charge, vous évitez les temps d'arrêt potentiels si votre équilibreur de charge n'est pas disponible ou si vous devez les supprimer pour des raisons de maintenance.

Voici un schéma d'une configuration de base haute disponibilité:

HA Setup

Dans cet exemple, vous avez plusieurs équilibreurs de charge (un actif et un ou plusieurs passifs) derrière une adresse IP statique qui peut être remappée d'un serveur à un autre. Les demandes client sont acheminées de l'IP statique à l'équilibreur de charge actif, puis à vos serveurs principaux. Pour en savoir plus, lisezthis section of How To Use Floating IPs.

Configuration de la mise en cache proxy pour réduire les temps de réponse

La mise en mémoire tampon peut aider à libérer le serveur principal pour lui permettre de traiter davantage de demandes, mais Nginx offre également un moyen de mettre en cache le contenu des serveurs principaux, éliminant ainsi le besoin de se connecter en amont pour de nombreuses demandes.

Configuration d'un cache de proxy

Pour configurer un cache à utiliser pour le contenu proxy, nous pouvons utiliser la directiveproxy_cache_path. Cela créera une zone dans laquelle les données renvoyées par les serveurs mandatés peuvent être conservées. La directiveproxy_cache_path doit être définie dans le contexte http.

Dans l'exemple ci-dessous, nous allons configurer cette directive et certaines directives connexes pour configurer notre système de mise en cache.

# http context

proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;

Avec la directiveproxy_cache_path, nous avons défini un répertoire sur le système de fichiers où nous voudrions stocker notre cache. Dans cet exemple, nous avons choisi le répertoire/var/lib/nginx/cache. Si ce répertoire n'existe pas, vous pouvez le créer avec la permission et la propriété appropriées en tapant:

sudo mkdir -p /var/lib/nginx/cache
sudo chown www-data /var/lib/nginx/cache
sudo chmod 700 /var/lib/nginx/cache

Le paramètrelevels= spécifie comment le cache sera organisé. Nginx créera une clé de cache en hachant la valeur d'une clé (configurée ci-dessous). Les niveaux que nous avons sélectionnés ci-dessus indiquent qu'un répertoire à caractère unique (ce sera le dernier caractère de la valeur hachée) avec un sous-répertoire à deux caractères (extrait des deux caractères suivants à partir de la fin de la valeur hachée). En règle générale, vous n’aurez pas à vous soucier des détails, mais cela aide Nginx à trouver rapidement les valeurs pertinentes.

Le paramètrekeys_zone= définit le nom de cette zone de cache, que nous avons appeléebackcache. C’est également ici que nous définissons le nombre de métadonnées à stocker. Dans ce cas, nous stockons 8 Mo de clés. Nginx peut stocker environ 8 000 entrées pour chaque mégaoctet. Le paramètremax_size définit la taille maximale des données réelles mises en cache.

Une autre directive que nous utilisons ci-dessus estproxy_cache_key. Ceci est utilisé pour définir la clé qui sera utilisée pour stocker les valeurs mises en cache. Cette même clé est utilisée pour vérifier si une demande peut être servie à partir du cache. Nous définissons ceci avec une combinaison du schéma (http ou https), de la méthode de requête HTTP, ainsi que de l'hôte et de l'URI demandés.

La directiveproxy_cache_valid peut être spécifiée plusieurs fois. Cela nous permet de configurer la durée de stockage des valeurs en fonction du code d'état. Dans notre exemple, nous stockons les succès et les redirections pendant 10 minutes et expirons le cache pour 404 réponses toutes les minutes.

Nous avons maintenant configuré la zone de cache, mais nous devons toujours indiquer à Nginx quand utiliser le cache.

Aux endroits où nous utilisons un serveur dorsal comme proxy, nous pouvons configurer l’utilisation de ce cache:

# server context

location /proxy-me {
    proxy_cache backcache;
    proxy_cache_bypass $http_cache_control;
    add_header X-Proxy-Cache $upstream_cache_status;

    proxy_pass http://backend;
}

. . .

En utilisant la directiveproxy_cache, nous pouvons spécifier que la zone de cache debackcache doit être utilisée pour ce contexte. Nginx vérifiera ici si une entrée est valide avant de passer au backend.

La directiveproxy_cache_bypass est définie sur la variable$http_cache_control. Cela contiendra un indicateur indiquant si le client demande explicitement une nouvelle version de la ressource, non mise en cache. La définition de cette directive permet à Nginx de gérer correctement ces types de demandes client. Aucune autre configuration n'est requise.

Nous avons également ajouté un en-tête supplémentaire appeléX-Proxy-Cache. Nous définissons cet en-tête sur la valeur de la variable$upstream_cache_status. Fondamentalement, cela définit un en-tête qui nous permet de voir si la demande a abouti à un succès dans le cache, à un manque de cache ou si le cache a été explicitement ignoré. Ceci est particulièrement utile pour le débogage, mais constitue également une information utile pour le client.

Remarques sur les résultats de la mise en cache

La mise en cache peut considérablement améliorer les performances de votre proxy. Cependant, il convient de garder à l'esprit les considérations suivantes lors de la configuration du cache.

Tout d'abord, toutes les données relatives à l'utilisateur doiventnot être mises en cache. Cela pourrait entraîner la présentation des données d’un utilisateur à un autre utilisateur. Si votre site est complètement statique, ce n'est probablement pas un problème.

Si votre site contient des éléments dynamiques, vous devrez en rendre compte dans les serveurs principaux. La façon dont vous gérez cela dépend de l’application ou du serveur qui gère le traitement du backend. Pour le contenu privé, vous devez définir l'en-têteCache-Control sur «no-cache», «no-store» ou «private» selon la nature des données:

  • no-cache: indique que la réponse ne doit pas être à nouveau servie sans vérifier au préalable que les données n'ont pas changé sur le backend. Ceci peut être utilisé si les données sont dynamiques et importantes. Un en-tête de métadonnées hachées ETag est vérifié à chaque demande et la valeur précédente peut être servie si le système retourne la même valeur de hachage.

  • no-store: indique qu'à aucun moment les données reçues ne doivent être mises en cache. C'est l'option la plus sûre pour les données privées, car cela signifie que les données doivent être récupérées à partir du serveur à chaque fois.

  • private: cela indique qu'aucun espace de cache partagé ne doit mettre en cache ces données. Cela peut être utile pour indiquer que le navigateur d’un utilisateur peut mettre les données en cache, mais le serveur proxy ne doit pas considérer ces données comme valides pour les demandes ultérieures.

  • public: cela indique que la réponse est des données publiques qui peuvent être mises en cache à tout moment de la connexion.

Un en-tête associé qui peut contrôler ce comportement est l'en-têtemax-age, qui indique le nombre de secondes pendant lesquelles une ressource doit être mise en cache.

Le fait de définir correctement ces en-têtes, en fonction de la sensibilité du contenu, vous aidera à tirer parti du cache tout en préservant la sécurité de vos données personnelles et la fraîcheur de vos données dynamiques.

Si votre backend utilise également Nginx, vous pouvez en définir une partie en utilisant la directiveexpires, qui définira lesmax-age pourCache-Control:

location / {
    expires 60m;
}

location /check-me {
    expires -1;
}

Dans l'exemple ci-dessus, le premier bloc permet de mettre le contenu en cache pendant une heure. Le deuxième bloc définit l'en-têteCache-Control sur «no-cache». Pour définir d'autres valeurs, vous pouvez utiliser la directiveadd_header, comme ceci:

location /private {
    expires -1;
    add_header Cache-Control "no-store";
}

Conclusion

Nginx est avant tout un proxy inverse, qui peut également fonctionner en tant que serveur Web. En raison de cette décision de conception, la transmission par proxy des demandes à d'autres serveurs est relativement simple. Nginx est cependant très flexible, permettant un contrôle plus complexe de votre configuration de proxy si vous le souhaitez.