Identification et résolution des goulots d'étranglement de performance Nginx : un guide de dépannage

Diagnostiquez les goulots d'étranglement Nginx avec les journaux, les métriques de statut, les vérifications système et des correctifs pratiques pour le CPU, la latence, la mémoire et les connexions.

Identification et résolution des goulots d'étranglement de performance Nginx : un guide de dépannage

Les problèmes de performance Nginx se manifestent généralement de manière simple : les pages deviennent lentes, les appels API commencent à expirer, le CPU augmente, ou les utilisateurs commencent à voir des erreurs 502 et 504. La difficulté réside dans le fait de déterminer si Nginx est le goulot d'étranglement ou s'il est simplement le premier service à se plaindre assez fort.

Lorsque je dépanne Nginx, j'essaie de ne pas commencer par modifier les directives. Je pose d'abord quelques questions simples. La latence a-t-elle augmenté pour toutes les routes ou seulement pour celles qui atteignent un amont ? Les fichiers statiques sont-ils également lents ? Les erreurs ont-elles commencé après un déploiement, un pic de trafic, un changement de certificat ou une modification de la journalisation ? Ce contexte permet généralement de gagner plus de temps que de copier un bloc de réglage d'un ancien article.

Comprendre les métriques de performance Nginx

Avant de se plonger dans le dépannage, il est crucial de comprendre ce qui constitue un goulot d'étranglement de performance et quelles métriques sont des indicateurs clés. Un goulot d'étranglement se produit lorsqu'un composant de votre système limite la capacité ou la vitesse globale. Pour Nginx, cela concerne souvent sa capacité à traiter les requêtes, gérer les connexions ou servir efficacement le contenu.

Les métriques clés à surveiller incluent :

  • Connexions actives : Le nombre de connexions client actuellement traitées par Nginx.
  • Requêtes par seconde (RPS) : Le taux auquel Nginx sert les requêtes.
  • Latence des requêtes : Le temps nécessaire à Nginx pour répondre à une requête client.
  • Utilisation du CPU : Le pourcentage de ressources CPU consommées par les processus workers Nginx.
  • Utilisation de la mémoire : La quantité de RAM utilisée par les processus Nginx.
  • E/S réseau : Le taux de transfert de données entrant et sortant du serveur Nginx.
  • E/S disque : Pertinent si Nginx sert directement des fichiers statiques ou journalise de manière extensive.

Outils Nginx intégrés pour le diagnostic

Nginx offre plusieurs fonctionnalités pour vous aider à surveiller son état opérationnel et à collecter des données de performance.

Utilisation du module stub_status

Le module stub_status fournit des informations de base mais vitales sur l'état actuel de Nginx. C'est un excellent premier arrêt pour un aperçu rapide de l'activité du serveur.

Activation de stub_status

Pour activer stub_status, ajoutez le bloc de configuration suivant à votre nginx.conf (généralement dans le bloc server pour votre point de terminaison de surveillance) :

server {
    listen 80;
    server_name monitoring.example.com;

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1; # Autoriser l'accès uniquement depuis localhost
        deny all;
    }
}

Après avoir modifié la configuration, rechargez Nginx :

sudo nginx -t # Tester la configuration
sudo nginx -s reload # Recharger Nginx

Interprétation de la sortie stub_status

Accédez à la page de statut (par exemple, http://localhost/nginx_status) pour voir une sortie similaire à celle-ci :

Active connections: 291
server accepts handled requests
 1162447 1162447 4496426
Reading: 6 Writing: 17 Waiting: 268

Voici ce que chaque métrique signifie :

  • Active connections : Le nombre actuel de connexions client actives, y compris les connexions Reading, Writing et Waiting.
  • accepts : Le nombre total de connexions que Nginx a acceptées.
  • handled : Le nombre total de connexions que Nginx a traitées. Idéalement, accepts et handled devraient être égaux. Si handled est significativement inférieur, cela peut indiquer des limitations de ressources (par exemple, la limite worker_connections).
  • requests : Le nombre total de requêtes client que Nginx a traitées.
  • Reading : Le nombre de connexions pour lesquelles Nginx est en train de lire l'en-tête de la requête.
  • Writing : Le nombre de connexions pour lesquelles Nginx est en train d'écrire la réponse au client.
  • Waiting : Le nombre de connexions client inactives en attente d'une requête (par exemple, connexions keep-alive). Un nombre élevé ici peut indiquer une utilisation efficace de keep-alive, mais aussi que les processus workers sont occupés à attendre, ce qui peut être préoccupant si les connexions actives sont faibles et les ressources limitées.

Exploitation de l'API Nginx Plus pour les métriques avancées

Pour les utilisateurs de Nginx Plus, l'API Nginx Plus fournit une interface JSON en temps réel plus détaillée pour la surveillance. Cette API offre des métriques granulaires pour les zones, les serveurs, les amonts, les caches, etc., ce qui la rend inestimable pour une analyse approfondie des performances et l'intégration avec des tableaux de bord de surveillance.

Activation de l'API Nginx Plus

Configurez un emplacement pour l'API dans votre configuration Nginx Plus :

http {
    server {
        listen 8080;

        location /api {
            api write=on;
            allow 127.0.0.1; # Restreindre l'accès pour des raisons de sécurité
            deny all;
        }

        location /api.html {
            root /usr/share/nginx/html;
        }
    }
}

Rechargez Nginx et accédez à http://localhost:8080/api pour voir la sortie JSON. Cette API fournit des données étendues, y compris des statistiques de connexion détaillées, les temps de traitement des requêtes, la santé des amonts et les performances du cache, permettant un dépannage beaucoup plus fin que stub_status.

Journaux d'accès et d'erreurs Nginx

Les journaux Nginx sont une mine d'informations pour le dépannage des performances. Ils enregistrent chaque requête et toute erreur rencontrée.

Configuration de la journalisation détaillée

Vous pouvez personnaliser votre log_format pour inclure des métriques de performance utiles comme le temps de traitement de la requête ($request_time) et le temps de réponse amont ($upstream_response_time).

http {
    log_format perf_log '$remote_addr - $remote_user [$time_local] "$request" ' 
                        '$status $body_bytes_sent "$http_referer" ' 
                        '"$http_user_agent" "$http_x_forwarded_for" ' 
                        'request_time:$request_time upstream_response_time:$upstream_response_time ' 
                        'upstream_addr:$upstream_addr';

    access_log /var/log/nginx/access.log perf_log;
    error_log /var/log/nginx/error.log warn;

    # Exemple pour journaliser les requêtes plus lentes qu'un seuil
    # C'est un peu plus avancé et peut nécessiter un module personnalisé ou un outil séparé pour analyser.
    # Il est souvent plus facile d'analyser le access_log principal pour les requêtes lentes.
}

Identification des requêtes lentes et des erreurs

  • Requêtes lentes : Utilisez des outils comme grep ou awk pour analyser vos journaux d'accès à la recherche de requêtes dépassant un certain seuil de $request_time ou $upstream_response_time. Cela aide à identifier les applications problématiques ou les services externes.
    awk 'match($0, /request_time:([0-9.]+)/, m) && m[1] > 1.0 {print $0}' /var/log/nginx/access.log
    
    Cela évite de dépendre d'un numéro de champ de journal fixe, qui change dès que le chemin de la requête, l'agent utilisateur ou le référent contient des espaces.
  • Erreurs : Surveillez error.log pour les problèmes critiques comme "upstream timed out", "no live upstreams" ou "too many open files". Ces erreurs pointent directement vers des problèmes de backend ou des limitations de ressources Nginx.

Outils de surveillance système externes

Les performances de Nginx sont souvent liées aux ressources du serveur sous-jacent. La surveillance au niveau système fournit un contexte crucial.

  • Utilisation du CPU (top, htop, mpstat) : Une utilisation élevée du CPU par les processus workers Nginx peut indiquer une configuration complexe (expressions régulières, poignées de main SSL), un code inefficace ou simplement une charge élevée.
    top -c # Affiche les processus triés par utilisation du CPU
    
  • Utilisation de la mémoire (free -h, htop) : Une consommation de mémoire excessive peut indiquer des tailles de tampon importantes (proxy_buffers), des fuites de mémoire ou un nombre inhabituellement élevé de connexions actives.
    free -h # Affiche l'utilisation de la mémoire en format lisible
    
  • E/S disque (iostat, iotop) : Pertinent si Nginx sert beaucoup de contenu statique ou journalise de manière extensive. Des E/S disque élevées peuvent signifier un goulot d'étranglement dans le stockage ou une journalisation excessive.
    iostat -x 1 10 # Affiche les statistiques disque étendues chaque seconde pendant 10 fois
    
  • E/S réseau (netstat, ss, iftop) : Surveillez le trafic réseau pour détecter une saturation ou des retransmissions excessives, ce qui pourrait indiquer des goulots d'étranglement réseau ou des problèmes entre Nginx et les clients/amonts.
    netstat -antp | grep nginx # Affiche les connexions Nginx
    

Goulots d'étranglement de performance Nginx courants et résolutions

Armé des données de surveillance, examinons les problèmes courants et comment les résoudre.

1. Utilisation élevée du CPU

Symptômes : top montre que les processus workers Nginx consomment un pourcentage élevé de CPU, même avec une charge modérée.

Causes :

  • Trop peu de processus workers pour les CPU multi-cœurs : Nginx pourrait ne pas utiliser tous les cœurs disponibles.
  • Instructions if ou expressions régulières complexes : Des regex trop complexes ou de nombreuses instructions if dans la configuration peuvent être gourmandes en CPU.
  • Configuration SSL/TLS inefficace : Utilisation de chiffrements faibles qui nécessitent plus de CPU, ou absence d'exploitation de l'accélération matérielle si disponible.
  • Journalisation excessive : Écriture de trop de données sur le disque, surtout avec des règles log_format complexes.
  • Surcharge TLS, de compression ou de traitement des requêtes : Des poignées de main TLS coûteuses, des niveaux de compression élevés, des règles de réécriture lourdes ou des en-têtes de requête très volumineux peuvent faire monter le CPU.

Résolutions :

  • Optimiser worker_processes : Définissez worker_processes auto; (recommandé) ou au nombre de cœurs CPU. Chaque processus worker est monothread et peut utiliser pleinement un cœur CPU.
    worker_processes auto;
    
  • Simplifier la configuration : Examinez les instructions if et les regex. Envisagez d'utiliser des directives map ou try_files pour une logique plus simple.
  • Optimiser SSL/TLS : Utilisez des paramètres TLS modernes et activez ssl_session_cache et ssl_session_timeout le cas échéant pour réduire le travail de poignée de main répété.
  • Contrôler la journalisation : Utilisez des journaux d'accès mis en mémoire tampon ou désactivez les journaux d'accès pour les actifs statiques bruyants si vous n'avez pas besoin d'enregistrements par requête à cet endroit.
  • Enquêter sur le backend : Si Nginx attend, le goulot d'étranglement est en amont. Optimisez l'application backend.

2. Temps de réponse lents

Symptômes : $request_time ou $upstream_response_time élevés dans les journaux ; les pages se chargent lentement.

Causes :

  • Problèmes de serveur amont (backend) : La cause la plus courante. Le serveur d'application est lent à générer les réponses.
  • Transferts de fichiers volumineux sans optimisation appropriée : Service de fichiers statiques volumineux sans sendfile ou gzip.
  • Latence réseau : Réseau lent entre le client et Nginx, ou entre Nginx et l'amont.
  • Absence de mise en cache : Récupération répétée de contenu dynamique.

Résolutions :

  • Optimiser les vérifications de santé et les délais d'attente amont : Configurez proxy_read_timeout, proxy_connect_timeout et proxy_send_timeout. Implémentez des vérifications de santé pour les serveurs amont.
    location / {
        proxy_pass http://backend_app;
        proxy_read_timeout 90s; # Ajuster selon les besoins
        proxy_connect_timeout 5s;
    }
    
  • Activer la compression gzip : Pour le contenu textuel, gzip réduit considérablement la taille de transfert.
    gzip on;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    
  • Activer sendfile et tcp_nodelay : Pour un service efficace des fichiers statiques.
    sendfile on;
    tcp_nodelay on;
    
  • Implémenter la mise en cache : Utilisez proxy_cache pour le contenu dynamique ou définissez des en-têtes expires pour les actifs statiques.
    # Exemple pour les actifs statiques
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires 30d;
        log_not_found off;
    }
    

3. Erreurs de connexion / Connexions maximales atteintes

Symptômes : Les clients reçoivent des échecs de connexion, des réponses 502 ou 504, ou des délais d'attente intermittents. stub_status peut montrer que les connexions acceptées augmentent rapidement, et le journal des erreurs peut mentionner worker_connections are not enough, too many open files ou des échecs de connexion amont.

Causes :

  • Limite worker_connections atteinte : Nginx ne peut pas accepter de nouvelles connexions.
  • Trop de fichiers ouverts (ulimit) : La limite du système d'exploitation pour les descripteurs de fichier est atteinte.
  • Saturation du backend : Les serveurs amont sont submergés et n'acceptent pas les connexions.
  • DDoS ou trafic légitime inhabituellement élevé.

Résolutions :

  • Augmenter worker_connections : Définissez cette directive à une valeur élevée (par exemple, 10240 ou plus) dans le bloc events. Il s'agit du nombre maximum de connexions par processus worker.
    events {
        worker_connections 10240;
    }
    
  • Ajuster les limites des descripteurs de fichier : Augmentez la limite de fichiers ouverts du système d'exploitation. Ajoutez worker_rlimit_nofile 65535; à nginx.conf si approprié, et définissez la limite de service via systemd avec LimitNOFILE=65535 sur la plupart des distributions Linux modernes.
  • Optimiser keepalive_timeout : Des délais d'attente keep-alive longs peuvent monopoliser inutilement les processus workers si les clients ne réutilisent pas les connexions. Raccourcissez-le si les connexions Waiting sont élevées et les requests faibles.
    keepalive_timeout 15s; # La valeur par défaut est 75s
    
  • Implémenter l'équilibrage de charge et la mise à l'échelle : Distribuez le trafic sur plusieurs serveurs backend. Envisagez les capacités d'équilibrage de charge de Nginx (round-robin, least-connected, ip-hash).
  • Limitation de débit : Utilisez les modules limit_req ou limit_conn pour protéger votre serveur contre les requêtes ou connexions excessives provenant de clients uniques.

4. Utilisation élevée de la mémoire

Symptômes : Les processus workers Nginx consomment une quantité importante de RAM ; le serveur peut swapper de manière excessive.

Causes :

  • Tailles de tampon importantes : proxy_buffers, client_body_buffer_size, fastcgi_buffers configurés trop haut.
  • Mise en cache extensive : Tailles proxy_cache_path importantes.
  • Nombreuses connexions actives : Chaque connexion nécessite une certaine mémoire.

Résolutions :

  • Ajuster les tailles de tampon : N'augmentez les tailles de tampon que lorsque les journaux montrent un véritable problème de tampon, comme des en-têtes de réponse trop volumineux pour le proxy ou le tampon FastCGI configuré. 413 Request Entity Too Large est contrôlé par les limites du corps de la requête telles que client_max_body_size, et non par les tampons de réponse proxy.
    proxy_buffer_size 4k;
    proxy_buffers 8 8k;
    
  • Optimiser la mise en cache : Gérez les tailles de cache et les politiques d'éviction (paramètres proxy_cache_path).
  • Revoir keepalive_timeout : Comme mentionné précédemment, un keepalive_timeout excessivement long peut maintenir les processus workers et leur mémoire associée actifs pour des connexions inactives.

Bonnes pratiques de configuration Nginx pour les performances

Au-delà du dépannage de problèmes spécifiques, ces bonnes pratiques générales aident à maintenir des performances Nginx optimales :

  • worker_processes auto; : Utilisez tous les cœurs CPU.
  • worker_connections : Définissez une valeur qui correspond à la concurrence attendue et aux limites des descripteurs de fichier. 4096 ou 8192 est un point de départ courant pour les serveurs occupés, mais la bonne valeur dépend de la charge de travail.
  • sendfile on; : Pour un service efficace des fichiers statiques.
  • tcp_nodelay on; : Assure la transmission immédiate des petits paquets, améliorant la latence pour les services interactifs.
  • keepalive_timeout : Ajustez en fonction du comportement du client ; 15 à 30 secondes est souvent un bon équilibre.
  • gzip on; : Activez la compression pour le contenu textuel.
  • proxy_buffering on; : En général, gardez la mise en mémoire tampon activée. Cela permet à Nginx de stocker la réponse du serveur amont sur le disque (si nécessaire) et de l'envoyer au client aussi rapidement que possible, libérant ainsi l'amont. Désactivez-la uniquement si le streaming en temps réel à faible latence est absolument critique et que vous comprenez les implications.
  • En-têtes expires : Mettez en cache le contenu statique de manière agressive côté client.
  • Minimisez les instructions if et les regex : Optez pour les directives map ou try_files pour de meilleures performances.
  • Utilisez access_log off; pour les fichiers statiques : Réduit les E/S disque pour les actifs statiques fréquemment consultés si la journalisation n'est pas strictement nécessaire.
  • HTTP/2 : Activez HTTP/2 pour les navigateurs modernes afin d'améliorer le multiplexage et la compression des en-têtes via HTTPS.
    listen 443 ssl http2;
    

Flux de travail et stratégie de dépannage

Face à un problème de performance, suivez une approche structurée :

  1. Définir une référence : Comprenez les métriques de fonctionnement normales (CPU, mémoire, connexions, RPS, latence) pendant les périodes saines.
  2. Surveiller les symptômes : Identifiez les symptômes spécifiques (par exemple, CPU élevé, requêtes lentes, erreurs de connexion) et utilisez des outils (stub_status, journaux, top) pour les confirmer.
  3. Émettre une hypothèse : Sur la base des symptômes, formulez une hypothèse sur la cause racine (par exemple, "Le CPU élevé est dû à une regex inefficace").
  4. Tester et analyser : Implémentez un changement (par exemple, simplifiez la regex) et surveillez son impact sur les métriques. Analysez les nouvelles entrées de journal ou la sortie stub_status.
  5. Itérer : Si le problème persiste, affinez votre hypothèse et répétez le processus.
  6. Documenter : Conservez des enregistrements des modifications apportées et de leurs effets pour référence future.

Les meilleures corrections de performance Nginx sont généralement ennuyeuses : prouvez où se trouve le retard, changez une chose et surveillez la même métrique par la suite. Si $upstream_response_time est élevé, réglez le chemin de l'application avant de blâmer Nginx. Si les fichiers statiques sont lents alors que le temps amont est vide, examinez les paramètres de disque, réseau, compression et fichiers statiques. Si les erreurs mentionnent des descripteurs de fichier ou des connexions workers, corrigez ces limites par paire. Cette habitude maintient le dépannage ancré dans des preuves plutôt que dans le folklore.