Liste de contrôle essentielle pour l'optimisation des performances Nginx sur les sites à fort trafic

Une liste de contrôle pratique des performances Nginx pour les workers, connexions, tampons, mise en cache, compression, journaux, délais d'attente, TLS et fichiers statiques.

Liste de contrôle essentielle pour l'optimisation des performances Nginx sur les sites à fort trafic

L'optimisation des performances de Nginx est plus simple lorsqu'on la traite comme une liste de contrôle, et non comme un jeu de devinettes. Commencez par les limites qui déterminent la quantité de trafic que Nginx peut accepter, puis élargissez aux tampons, à la mise en cache, à la compression, à la journalisation, aux délais d'attente, à TLS et aux services backend qui se cachent derrière.

Ne copiez pas toutes les directives ici en production d'un coup. Une bonne liste de contrôle pour l'optimisation des performances de Nginx vous aide à décider quoi vérifier, pourquoi c'est important et ce qui peut mal tourner si vous en faites trop. Le réglage approprié pour un site de documentation principalement statique n'est pas le même que pour une API à long polling ou un service de téléchargement de fichiers.

1. Optimiser les processus workers et les connexions

Nginx utilise un modèle de processus maître-worker. Le processus maître lit la configuration et gère les processus workers, qui traitent les requêtes clients réelles. Configurer correctement ces éléments peut considérablement améliorer la concurrence et l'utilisation des ressources.

worker_processes

Cette directive détermine le nombre de processus workers que Nginx va générer. En général, le définir sur auto permet à Nginx de détecter le nombre de cœurs CPU et de générer un nombre égal de processus workers, ce qui est une bonne pratique courante.

worker_connections

Définit le nombre maximum de connexions simultanées qu'un seul processus worker peut ouvrir. Ce paramètre, combiné à worker_processes, détermine le nombre total théorique de connexions simultanées que Nginx peut gérer (worker_processes * worker_connections).

multi_accept

Permet à un processus worker d'accepter plusieurs nouvelles connexions à la fois, évitant ainsi les goulots d'étranglement potentiels sous forte charge.

# /etc/nginx/nginx.conf

worker_processes auto; # Généralement défini sur 'auto' ou le nombre de cœurs CPU

events {
    worker_connections 1024; # Ajuster en fonction de la capacité du serveur et de la charge attendue
    multi_accept on;
}

Astuce : Si le CPU est constamment élevé, augmenter worker_connections ne résoudra pas le problème tout seul. Vérifiez d'abord si le CPU provient des poignées de main TLS, de la compression, de la journalisation, du routage basé sur des expressions régulières ou de l'application en amont.

2. Gestion efficace des connexions

Optimiser la façon dont Nginx gère les connexions réseau peut réduire les frais généraux et améliorer la réactivité.

keepalive_timeout

Spécifie combien de temps une connexion keep-alive client reste ouverte. Réutiliser les connexions réduit les frais généraux liés à l'établissement de nouvelles connexions TCP et aux poignées de main SSL. Une valeur courante est de 15 à 65 secondes, selon l'interactivité de votre application.

sendfile

Permet le transfert direct de données entre les descripteurs de fichiers, contournant la mise en tampon dans l'espace utilisateur. Cela améliore considérablement les performances lors du service de fichiers statiques.

tcp_nopush

Fonctionne avec sendfile. Nginx essaie d'envoyer l'en-tête HTTP et le début du fichier dans un seul paquet. Ensuite, il envoie les données en paquets complets. Cela réduit le nombre de paquets envoyés.

tcp_nodelay

Ordonne à Nginx d'envoyer les données dès qu'elles sont disponibles, sans mise en tampon. Ceci est bénéfique pour les applications interactives où une faible latence est plus critique que la maximisation du débit (par exemple, les applications de chat ou les mises à jour en temps réel).

http {
    keepalive_timeout 65; # Connexions keep-alive pendant 65 secondes
    sendfile on;
    tcp_nopush on; # Nécessite sendfile activé
    tcp_nodelay on; # Utile pour le proxy de contenu dynamique
}

3. Optimisation des tampons

Nginx utilise des tampons pour gérer les requêtes clients et les réponses des serveurs en amont (comme les serveurs d'application). Dimensionner correctement ces tampons peut éviter les entrées/sorties disque inutiles, réduire l'utilisation de la mémoire et améliorer le débit.

Tampons clients

  • client_body_buffer_size : Taille du tampon pour le corps des requêtes clients. Si un corps dépasse cette taille, il est écrit dans un fichier temporaire.
  • client_header_buffer_size : Taille du tampon pour la première ligne et les en-têtes d'une requête client.
  • large_client_header_buffers : Définit le nombre et la taille des tampons plus grands pour lire les en-têtes des requêtes clients. Utile pour les requêtes avec de nombreux cookies ou des en-têtes referer longs.

Tampons proxy (pour les configurations de proxy inverse)

  • proxy_buffers : Le nombre et la taille des tampons utilisés pour lire les réponses du serveur proxy.
  • proxy_buffer_size : La taille du premier tampon pour lire la réponse. Généralement plus petit, car il ne contient souvent que les en-têtes.
  • proxy_busy_buffers_size : La quantité maximale de tampons de réponse pouvant être dans l'état 'occupé' (en cours d'envoi au client) à un moment donné.

Tampons FastCGI (pour PHP-FPM, etc.)

  • fastcgi_buffers : Le nombre et la taille des tampons utilisés pour lire les réponses du serveur FastCGI.
  • fastcgi_buffer_size : La taille du premier tampon pour lire la réponse.
http {
    # Tampons clients
    client_body_buffer_size 1M; # Ajuster en fonction de la taille attendue du corps de la requête (ex. téléchargements de fichiers)
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k; # 4 tampons, chacun de 8 Ko

    # Tampons proxy (si Nginx agit comme proxy inverse)
    proxy_buffers 8 16k; # 8 tampons, chacun de 16 Ko
    proxy_buffer_size 16k; # Premier tampon de 16 Ko
    proxy_busy_buffers_size 16k; # Max 16 Ko de tampons occupés

    # Tampons FastCGI (si Nginx fonctionne avec PHP-FPM)
    fastcgi_buffers 16 16k; # Point de départ pour de nombreuses applications PHP-FPM
    fastcgi_buffer_size 16k; # Premier tampon de 16 Ko
}

Attention : Définir des tampons trop petits peut entraîner des entrées/sorties disque et une dégradation des performances. Les définir trop grands peut consommer une mémoire excessive. Trouvez un équilibre par des tests.

4. Mettre en œuvre des stratégies de mise en cache robustes

La mise en cache est l'un des moyens les plus efficaces d'améliorer les performances et de réduire la charge sur vos serveurs backend. Nginx peut servir de puissant cache de contenu.

proxy_cache_path

Définit le chemin du répertoire de cache, sa taille, le nombre de niveaux de sous-répertoires et la durée de conservation des éléments inactifs dans le cache.

proxy_cache

Active la mise en cache pour un bloc location donné, en référençant la zone définie dans proxy_cache_path.

proxy_cache_valid

Définit la durée pendant laquelle Nginx doit mettre en cache les réponses avec des codes d'état HTTP spécifiques.

proxy_cache_revalidate

Lorsqu'il est activé, Nginx utilise les en-têtes If-Modified-Since et If-None-Match pour revalider le contenu mis en cache avec le backend, réduisant ainsi l'utilisation de la bande passante.

proxy_cache_use_stale

Ordonne à Nginx de servir le contenu mis en cache obsolète si le serveur backend est en panne, ne répond pas ou rencontre des erreurs. Cela améliore considérablement la disponibilité.

expires

Définit les en-têtes Cache-Control et Expires pour la mise en cache côté client des fichiers statiques. Cela minimise les requêtes répétées à Nginx.

http {
    # Définir une zone de cache proxy dans le bloc http
    proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=10g;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://my_upstream_backend;
            proxy_cache my_cache; # Activer la mise en cache pour cet emplacement
            proxy_cache_valid 200 302 10m; # Mettre en cache les réponses réussies pendant 10 minutes
            proxy_cache_valid 404 1m; # Mettre en cache les 404 pendant 1 minute
            proxy_cache_revalidate on;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            add_header X-Cache-Status $upstream_cache_status; # Aide au débogage
        }

        # Mettre en cache les fichiers statiques dans le navigateur pour une période plus longue
        location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
            expires 30d; # Mettre en cache pendant 30 jours
            add_header Cache-Control "public, no-transform";
            # Pour les fichiers statiques, envisagez de servir directement depuis Nginx s'ils ne sont pas proxy
            root /var/www/html;
        }
    }
}

5. Activer la compression Gzip

Compresser les réponses avant de les envoyer aux clients peut réduire considérablement l'utilisation de la bande passante et améliorer les temps de chargement des pages, en particulier pour le contenu textuel.

gzip on

Active la compression gzip.

gzip_comp_level

Définit le niveau de compression (1-9). Le niveau 1 est le plus rapide avec moins de compression ; le niveau 9 est le plus lent avec une compression maximale. Le niveau 6 offre généralement un bon équilibre.

gzip_types

Spécifie les types MIME qui doivent être compressés. Incluez les types courants de texte, CSS, JavaScript et JSON.

gzip_min_length

Définit la longueur minimale d'une réponse (en octets) pour laquelle la compression doit être activée. Les petits fichiers ne bénéficient pas beaucoup de la compression et peuvent même être plus lents en raison des frais généraux de compression.

gzip_proxied

Ordonne à Nginx de compresser les réponses même si elles sont proxy. any est une valeur courante.

gzip_vary

Ajoute l'en-tête Vary: Accept-Encoding aux réponses, informant les proxies que la réponse peut différer en fonction de l'en-tête de requête Accept-Encoding.

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6; # Niveau de compression 1-9 (6 est un bon équilibre)
    gzip_buffers 16 8k; # 16 tampons, chacun de 8 Ko
    gzip_http_version 1.1; # Version HTTP minimale pour la compression
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
    gzip_min_length 1000; # Compresser uniquement les réponses de plus de 1 Ko
}

6. Optimiser la journalisation

Bien que les journaux soient essentiels pour la surveillance et le dépannage, une journalisation excessive ou non optimisée peut introduire des entrées/sorties disque importantes, en particulier sur les sites à fort trafic.

access_log

  • Désactiver pour les actifs statiques : Pour le contenu statique très consulté (images, CSS, JS), désactiver access_log peut économiser beaucoup d'entrées/sorties.
  • Mise en tampon : Nginx peut mettre en mémoire tampon les entrées de journal avant de les écrire sur le disque, réduisant ainsi la fréquence des écritures disque. Les paramètres buffer et flush sont utilisés ici.

error_log

Définissez le niveau de journalisation approprié (crit, error, warn, info, debug). Pour la production, warn ou error est généralement suffisant pour capturer les problèmes critiques sans inonder les journaux.

http {
    server {
        # Journal d'accès par défaut pour le contenu dynamique
        access_log /var/log/nginx/access.log main;

        location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
            access_log off; # Désactiver la journalisation pour les fichiers statiques courants
            expires 30d;
        }
    }

    # Exemple de journal d'accès tamponné pour le contexte HTTP principal
    # access_log /var/log/nginx/access.log main buffer=16k flush=5s;
    error_log /var/log/nginx/error.log warn; # Journaliser uniquement les avertissements et les erreurs
}

7. Ajuster les délais d'attente

Des délais d'attente correctement configurés empêchent Nginx de conserver trop longtemps les connexions inactives, libérant ainsi des ressources.

Délais d'attente côté client

  • client_body_timeout : Combien de temps Nginx attend qu'un client envoie le corps de la requête.
  • client_header_timeout : Combien de temps Nginx attend qu'un client envoie l'en-tête de la requête.
  • send_timeout : Combien de temps Nginx attend qu'un client accepte la réponse après son envoi.

Délais d'attente proxy/FastCGI (le cas échéant)

  • proxy_connect_timeout : Délai d'attente pour établir une connexion avec un serveur proxy.
  • proxy_send_timeout : Délai d'attente pour transmettre une requête au serveur proxy.
  • proxy_read_timeout : Délai d'attente pour lire une réponse du serveur proxy.
http {
    client_body_timeout 15s; # Le client a 15 secondes pour envoyer le corps
    client_header_timeout 15s; # Le client a 15 secondes pour envoyer les en-têtes
    send_timeout 15s; # Nginx a 15 secondes pour envoyer la réponse au client

    # Pour les scénarios proxy
    proxy_connect_timeout 5s; # 5 secondes pour se connecter à l'amont
    proxy_send_timeout 15s; # 15 secondes pour envoyer la requête à l'amont
    proxy_read_timeout 15s; # 15 secondes pour lire la réponse de l'amont

    # Pour les scénarios FastCGI
    fastcgi_connect_timeout 5s;
    fastcgi_send_timeout 15s;
    fastcgi_read_timeout 15s;
}

8. Optimisation SSL/TLS

Pour les sites activés HTTPS, l'optimisation des paramètres SSL/TLS est cruciale pour réduire la charge CPU et améliorer les performances des poignées de main.

ssl_session_cache et ssl_session_timeout

Activez la mise en cache des sessions SSL pour éviter la poignée de main TLS complète, coûteuse en calcul, pour les connexions suivantes du même client.

ssl_protocols et ssl_ciphers

Utilisez des protocoles TLS modernes comme TLSv1.2 et TLSv1.3. Soyez prudent avec les chaînes de chiffrement copiées : les chiffrements TLS 1.3 ne sont pas contrôlés de la même manière que les suites de chiffrement TLS plus anciennes, et les valeurs par défaut de la distribution sont souvent plus sûres que des exemples obsolètes provenant d'anciens guides.

ssl_stapling

Active l'agrafage OCSP, où Nginx récupère périodiquement la réponse OCSP de l'autorité de certification et l'"agrafe" à la poignée de main SSL/TLS. Cela réduit la latence côté client en évitant une requête OCSP distincte.

server {
    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/your_domain.crt;
    ssl_certificate_key /etc/nginx/ssl/your_domain.key;

    ssl_session_cache shared:SSL:10m; # Cache partagé pour 10 Mo de données de session
    ssl_session_timeout 10m; # Les sessions expirent après 10 minutes

    ssl_protocols TLSv1.2 TLSv1.3; # Utiliser des protocoles modernes et sécurisés
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
    ssl_prefer_server_ciphers on;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=300s; # Utiliser des résolveurs approuvés pour votre environnement
    resolver_timeout 5s;
}

9. Cache des fichiers ouverts

Nginx peut mettre en cache les descripteurs de fichiers pour les fichiers fréquemment consultés, réduisant ainsi le besoin d'appels système répétés pour ouvrir et fermer des fichiers.

open_file_cache

Active le cache, en spécifiant le nombre maximum d'éléments et la durée de conservation des éléments inactifs.

open_file_cache_valid

Définit la fréquence à laquelle le cache doit vérifier la validité de ses éléments.

open_file_cache_min_uses

Spécifie le nombre minimum de fois qu'un fichier doit être consulté pendant la période inactive pour rester dans le cache.

open_file_cache_errors

Détermine si Nginx doit mettre en cache les erreurs lors de l'ouverture de fichiers.

http {
    open_file_cache max=100000 inactive=60s; # Mettre en cache jusqu'à 100 000 descripteurs de fichiers pendant 60s
    open_file_cache_valid 80s; # Vérifier la validité toutes les 80 secondes
    open_file_cache_min_uses 1; # Mettre en cache les fichiers utilisés au moins une fois
    open_file_cache_errors on; # Mettre en cache les erreurs liées à l'ouverture de fichiers
}

10. Valider avec des signaux de trafic réels

Le dernier élément de la liste de contrôle est la mesure. Avant un changement, capturez une petite référence : latence des requêtes, taux de 5xx, connexions actives, CPU, mémoire, entrées/sorties disque, débit réseau et temps de réponse en amont. Après le changement, comparez les mêmes chiffres.

Pour un proxy inverse, $request_time et $upstream_response_time sont particulièrement utiles. Si les deux augmentent ensemble, le backend est probablement lent. Si $request_time est élevé alors que le temps en amont est faible ou vide, examinez la vitesse de téléchargement du client, le temps de transfert de la réponse, la mise en tampon, la compression ou la livraison de fichiers statiques. Si aucune métrique n'explique le problème, vérifiez le journal des erreurs et le système d'exploitation.

La séquence de réglage la plus sûre est simple : testez la configuration avec nginx -t, rechargez plutôt que redémarrez lorsque c'est possible, surveillez les journaux et revenez en arrière rapidement si la latence ou les erreurs évoluent dans la mauvaise direction. Nginx peut gérer beaucoup de trafic, mais seulement lorsque ses limites, le noyau et l'application en amont sont en accord les uns avec les autres.