Stratégies d'équilibrage de charge Nginx pour une haute disponibilité
Apprenez à assurer une haute disponibilité pour vos applications web avec l'équilibrage de charge Nginx. Ce guide explore les stratégies essentielles d'équilibrage de charge Nginx, notamment Round Robin, Weighted Round Robin, Least-Connected et IP Hash. Découvrez des exemples pratiques de configuration, comprenez les mécanismes de vérification de l'état et mettez en œuvre les meilleures pratiques pour garantir que vos applications restent accessibles et performantes sous des charges de trafic variables.
Stratégies d'équilibrage de charge Nginx pour une haute disponibilité
L'équilibrage de charge Nginx est généralement introduit après la première limite douloureuse : un serveur d'application est trop occupé, nécessite une maintenance ou tombe en panne d'une manière qui entraîne tout le site avec lui. Placer Nginx devant plusieurs backends vous donne de la marge pour répartir les requêtes, drainer un serveur et survivre aux pannes ordinaires.
Ce n'est pas une haute disponibilité magique en soi. Nginx open source peut cesser d'envoyer du trafic vers un backend après des échecs de connexion, mais il ne comprend pas en profondeur si votre page de paiement, votre dépendance API ou votre connexion à la base de données est saine. Une bonne configuration combine la configuration en amont de Nginx, des délais d'attente raisonnables, des points de terminaison de santé au niveau de l'application, une surveillance externe et un processus de déploiement capable de supprimer rapidement un mauvais backend.
Comprendre l'équilibrage de charge
À la base, l'équilibrage de charge consiste à diriger intelligemment les requêtes des clients vers un pool de serveurs. Au lieu qu'un seul serveur gère tout le trafic, plusieurs serveurs travaillent de concert. Cela offre plusieurs avantages clés :
- Haute disponibilité : Si un serveur tombe en panne de manière détectable, d'autres peuvent continuer à traiter les requêtes.
- Évolutivité : À mesure que le trafic augmente, vous pouvez ajouter plus de serveurs au pool pour gérer la charge.
- Performances : La distribution du trafic empêche un seul serveur d'être surchargé, ce qui entraîne des temps de réponse plus rapides.
- Fiabilité : En supprimant les points de défaillance uniques, votre application devient plus robuste.
Nginx agit comme un proxy inverse dans une configuration d'équilibrage de charge. Il reçoit les requêtes entrantes des clients et les transmet à l'un des serveurs backend disponibles en fonction d'un algorithme configuré. Il reçoit également la réponse du serveur backend et la renvoie au client, rendant le processus transparent pour l'utilisateur final.
Directives d'équilibrage de charge Nginx
Nginx utilise des directives spécifiques dans son fichier de configuration (généralement nginx.conf ou des fichiers inclus à partir de celui-ci) pour définir des groupes de serveurs en amont et leur comportement d'équilibrage de charge.
Le bloc upstream
Le bloc upstream est utilisé pour définir un groupe de serveurs sur lequel Nginx équilibrera le trafic. Ce bloc est généralement placé dans le contexte http.
http {
upstream my_backend_servers {
# Les configurations du serveur vont ici
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://my_backend_servers;
}
}
}
À l'intérieur du bloc upstream, vous listez les serveurs backend en utilisant la directive server, en spécifiant leurs adresses IP ou noms d'hôte et ports.
upstream my_backend_servers {
server backend1.example.com;
server backend2.example.com;
server 192.168.1.100:8080;
}
La directive proxy_pass
La directive proxy_pass, utilisée dans un bloc location, pointe vers le groupe upstream que vous avez défini. Nginx utilisera ensuite l'algorithme d'équilibrage de charge configuré pour sélectionner un serveur de ce groupe pour chaque requête.
Algorithmes d'équilibrage de charge Nginx
Nginx prend en charge plusieurs algorithmes d'équilibrage de charge, chacun avec sa propre approche de distribution du trafic. L'algorithme par défaut est Round Robin.
1. Round Robin (par défaut)
Dans Round Robin, Nginx distribue les requêtes séquentiellement à chaque serveur du groupe upstream. Chaque serveur reçoit une part égale de la charge au fil du temps. C'est simple, efficace pour des serveurs identiques et la méthode la plus couramment utilisée.
Configuration :
upstream my_backend_servers {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
Avantages :
- Simple à mettre en œuvre et à comprendre.
- Distribue uniformément la charge si les serveurs ont une capacité similaire.
Inconvénients :
- Ne tient pas compte de la charge du serveur ou des temps de réponse. Un serveur lent peut encore recevoir des requêtes.
2. Round Robin pondéré
Le Round Robin pondéré vous permet d'attribuer un poids à chaque serveur. Les serveurs avec un poids plus élevé recevront une part proportionnellement plus importante du trafic. Ceci est utile lorsque vous avez des serveurs avec des capacités différentes (par exemple, un matériel plus puissant).
Configuration :
upstream my_backend_servers {
server backend1.example.com weight=3;
server backend2.example.com weight=1;
}
Dans cet exemple, backend1.example.com recevra trois fois plus de requêtes que backend2.example.com.
Avantages :
- Permet un équilibrage basé sur la capacité du serveur.
Inconvénients :
- Ne tient toujours pas compte de la charge du serveur en temps réel.
3. Least-Connected
L'algorithme Least-Connected dirige les requêtes vers le serveur ayant le moins de connexions actives. Cette méthode est plus dynamique car elle prend en compte la charge actuelle de chaque serveur.
Configuration :
Pour activer Least-Connected, vous ajoutez simplement le paramètre least_conn au bloc upstream :
upstream my_backend_servers {
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
Avantages :
- Distribue la charge plus intelligemment en tenant compte de la charge actuelle du serveur.
- Bon pour les applications avec des durées de connexion variables.
Inconvénients :
- Peut être légèrement plus complexe à gérer si le nombre de connexions fluctue rapidement.
4. IP Hash
Avec IP Hash, Nginx détermine quel serveur doit traiter une requête en fonction d'un hachage de l'adresse IP du client. Cela garantit que les requêtes d'une même adresse IP client sont systématiquement envoyées au même serveur backend. Ceci est crucial pour les applications qui reposent sur la persistance de session (sessions persistantes) sans utiliser de stockage de session partagé.
Configuration :
Ajoutez le paramètre ip_hash au bloc upstream :
upstream my_backend_servers {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
Avantages :
- Fournit une persistance de session prête à l'emploi.
Inconvénients :
- Peut entraîner une distribution inégale de la charge si de nombreux clients partagent une seule adresse IP (par exemple, derrière une passerelle NAT).
- Si un serveur tombe en panne, tous les clients hachés vers ce serveur seront affectés jusqu'à ce que le serveur soit de nouveau en ligne ou que le hachage soit recalculé (bien que Nginx tente de réacheminer).
5. Hachage générique
Similaire à IP Hash, le hachage générique vous permet de spécifier une clé pour le hachage. Cette clé peut être une variable comme $request_id, $cookie_jsessionid ou une combinaison de variables. Cela offre plus de flexibilité pour la persistance de session ou le routage basé sur des attributs de requête spécifiques.
Configuration :
upstream my_backend_servers {
hash $remote_addr consistent;
server backend1.example.com;
server backend2.example.com;
}
L'utilisation de consistent avec hash implémente le hachage cohérent, ce qui minimise la redistribution des clés lorsque l'ensemble des serveurs change.
Avantages :
- Très flexible pour une logique de routage personnalisée.
- Prend en charge le hachage cohérent pour une meilleure stabilité lors des changements de serveur.
Inconvénients :
- Nécessite une sélection minutieuse de la clé de hachage.
Vérifications de l'état et statut du serveur
Pour une haute disponibilité utile, Nginx doit éviter les backends qui échouent. La version open source le fait principalement de manière passive : elle remarque les tentatives échouées lors du proxy du trafic réel. Cela aide en cas d'hôtes morts, de connexions refusées et de certains cas de dépassement de délai. Ce n'est pas la même chose qu'une vérification de l'état active qui appelle /healthz toutes les quelques secondes avant que les utilisateurs n'accèdent au service.
max_fails et fail_timeout
Ces paramètres, ajoutés à la directive server dans un bloc upstream, contrôlent la façon dont Nginx traite les serveurs en échec.
max_fails: Le nombre de tentatives infructueuses pour communiquer avec un serveur dans une périodefail_timeoutspécifiée. Aprèsmax_failséchecs, le serveur est marqué comme indisponible.fail_timeout: La durée pendant laquelle un serveur est considéré comme indisponible. Après cette période, Nginx tentera de vérifier à nouveau son état.
Configuration :
upstream my_backend_servers {
server backend1.example.com max_fails=3 fail_timeout=30s;
server backend2.example.com max_fails=3 fail_timeout=30s;
}
Dans cet exemple, si backend1.example.com a trois tentatives infructueuses pendant la fenêtre d'échec, Nginx l'évite temporairement. Après le délai d'attente, Nginx peut réessayer. Les échecs sont basés sur les tentatives de connexion/proxy, et non sur une réponse de santé d'application personnalisée, sauf si vous utilisez des outils supplémentaires ou des fonctionnalités Nginx Plus.
Paramètre backup
Le paramètre backup désigne un serveur comme serveur de secours. Il ne recevra du trafic que si tous les autres serveurs actifs du groupe upstream sont indisponibles.
Configuration :
upstream my_backend_servers {
server backend1.example.com;
server backend2.example.com;
server backup.example.com backup;
}
Si backend1 et backend2 sont en panne, backup.example.com prendra le relais.
Vérifications de l'état Nginx Plus
Nginx Plus, la version commerciale, inclut des vérifications de l'état actives intégrées. Il peut périodiquement envoyer des requêtes aux backends, évaluer les réponses et supprimer les serveurs défaillants avant que le trafic utilisateur ne soit acheminé vers eux. Si vous utilisez Nginx open source, vous pouvez toujours construire un système solide, mais vous l'associez normalement à une surveillance externe, une découverte de services ou une automatisation qui modifie/supprime les cibles en amont.
Exemples pratiques de configuration
Mettons ces concepts en pratique avec des scénarios courants.
Scénario 1 : Équilibrage de charge Round Robin simple
Distribuez le trafic sur deux serveurs web identiques.
Configuration :
http {
upstream web_servers {
server 10.0.0.10;
server 10.0.0.11;
}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://web_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Explication :
upstream web_servers: Définit un groupe nomméweb_servers.server 10.0.0.10;etserver 10.0.0.11;: Spécifie les serveurs backend.proxy_pass http://web_servers;: Dirige le trafic vers le groupe en amontweb_servers.proxy_set_header: Ces directives sont cruciales pour transmettre les informations originales du client aux serveurs backend, ce qui est souvent nécessaire pour la journalisation ou la logique applicative.
Scénario 2 : Équilibrage de charge avec persistance de session (IP Hash)
Assurez-vous que les utilisateurs restent connectés au même serveur backend, utile pour les applications stockant les données de session localement.
N'utilisez ceci que lorsque vous comprenez le compromis. Si de nombreux utilisateurs passent par le même NAT de bureau, la passerelle d'un opérateur mobile ou un proxy d'entreprise, IP Hash peut envoyer trop de trafic vers un seul backend. Le stockage de session partagé, les cookies d'état sans état signés ou la réplication de session au niveau de l'application sont souvent plus propres que de se fier à la persistance de l'IP client.
Configuration :
http {
upstream app_servers {
ip_hash;
server 192.168.1.50:8000;
server 192.168.1.51:8000;
}
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://app_servers;
# ... autres directives proxy_set_header ...
}
}
}
Scénario 3 : Équilibrage de charge pondéré avec basculement
Dirigez plus de trafic vers un serveur plus puissant et ayez un serveur de secours prêt.
Configuration :
http {
upstream balanced_app {
server app_server_1.local weight=5;
server app_server_2.local weight=2;
server app_server_3.local backup;
}
server {
listen 80;
server_name staging.yourdomain.com;
location / {
proxy_pass http://balanced_app;
# ... autres directives proxy_set_header ...
}
}
}
Ici, app_server_1.local reçoit 5 parts du trafic, app_server_2.local en reçoit 2, et app_server_3.local ne sert les requêtes que si les deux autres sont indisponibles.
Meilleures pratiques et conseils
- Utilisez
proxy_set_header: Définissez toujours des en-têtes commeHost,X-Real-IP,X-Forwarded-ForetX-Forwarded-Protoafin que vos applications backend connaissent les détails du client d'origine. - Gardez Nginx à jour : Assurez-vous d'exécuter une version stable et à jour de Nginx pour des améliorations de sécurité et de performances.
- Surveillez les serveurs backend : Mettez en œuvre des outils de surveillance externes en plus des vérifications de l'état internes de Nginx. Nginx sait seulement s'il peut atteindre un serveur, pas nécessairement si l'application sur le serveur fonctionne correctement.
- Envisagez Nginx Plus : Pour les applications critiques, Nginx Plus offre des fonctionnalités avancées telles que les vérifications de l'état actives, la persistance de session et la surveillance de l'activité en direct, ce qui peut simplifier la gestion et améliorer la résilience.
- Équilibrage de charge DNS : Pour la distribution du trafic entre les régions ou plusieurs points d'entrée Nginx, le DNS peut aider, mais le basculement DNS dépend du comportement du résolveur et des TTL. Ne le traitez pas comme un basculement instantané.
- Terminaison SSL : Vous pouvez souvent terminer le SSL au niveau de l'équilibreur de charge (Nginx) pour décharger le traitement SSL de vos serveurs backend.
Un point de départ pratique
Pour deux ou trois serveurs d'application identiques, commencez par un round robin simple, des délais d'attente de proxy conservateurs et une journalisation en amont claire. Ajoutez max_fails et fail_timeout, puis testez ce qui se passe lorsque vous arrêtez un backend. N'attendez pas un incident réel pour apprendre comment Nginx se comporte.
Si les requêtes prennent des durées très différentes, essayez least_conn. Si un serveur est plus grand que les autres, utilisez des poids. Si l'application stocke l'état de session localement, corrigez la conception de la session si vous le pouvez ; utilisez ip_hash uniquement lorsque vous avez besoin d'un pont pratique.
La meilleure stratégie d'équilibrage de charge Nginx est celle qui correspond à la façon dont votre application échoue. Une VM morte, un backend lent, une version cassée et une panne de base de données semblent tous différents du point de vue du proxy. Configurez l'algorithme, puis prouvez le comportement en cas d'échec avec de petits tests avant d'appeler la configuration hautement disponible.