Optimisation des performances Nginx : gzip, cache et pool de connexions

La semaine dernière, une alerte : le temps de chargement de la page d’accueil d’un site e-commerce avait grimpé à 4 secondes. Chrome DevTools montrait un HTML de 120 Ko, CSS et JS à 350 Ko — tout en clair, sans compression. Pire : chaque requête frappait le backend, avec un taux de hits cache pitoyable de 12 %. Après une soirée de travail, j’ai passé 2 heures sur la config Nginx : gzip activé, stratégie de cache complétée, paramètres de pool ajustés. Le lendemain matin, la page d’accueil était à 1,6 s et le QPS backend avait chuté de près de moitié.
Ce genre de situation est très courant. Beaucoup installent Nginx et le laissent tourner : gzip désactivé par défaut, cache réduit à deux lignes, plafond de connexions par défaut. Au pic de trafic, le serveur suffoque.
Cet article rassemble les réglages de performance Nginx que j’ai validés en production. La compression gzip peut réduire le volume transféré de 60 à 80 % ; avec 95 % de hits cache, la charge backend baisse d’environ 90 % ; un pool de connexions bien dimensionné peut multiplier la concurrence par trois ou quatre. Je détaille chaque module, les pièges que j’ai rencontrés et les chiffres mesurés.
Chapitre 1 : configuration gzip — réduire le volume transféré
Pourquoi gzip compte autant ? Imaginez un HTML de 100 Ko : compressé, il peut tomber à 20-25 Ko. Les 75-80 Ko économisés, c’est un chargement plus rapide pour l’utilisateur et moins de coût bande passante pour vous.
J’ai pris conscience du problème sur un projet client : plus de 60 % d’utilisateurs mobiles, souvent en 4G. La page d’accueil mettait 3-4 s, taux de rebond à 70 %. Avec gzip, le volume transféré a chuté d’environ 70 % et le first paint est passé autour de 1,5 s.
1.1 Configuration de base : démarrer simplement
La config gzip Nginx n’est pas complexe — quelques lignes suffisent :
http {
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
}
gzip on active la compression. gzip_vary on ajoute Vary: Accept-Encoding dans la réponse : le CDN et le navigateur savent que le contenu dépend de la capacité de compression du client, ce qui évite les incohérences de cache.
gzip_min_length 1000 signifie : pas de compression sous 1 Ko — le gain est faible et le CPU gaspillé. gzip_types liste les MIME à compresser ; par défaut seul text/html l’est, il faut ajouter CSS, JS, JSON, XML, etc.
1.2 Configuration avancée : niveau de compression et types MIME
Le niveau de compression est un compromis. gzip_comp_level va de 1 à 9 : plus le chiffre est élevé, plus le taux de compression monte, mais aussi la charge CPU.
Tests que j’ai réalisés :
| Niveau | Taux HTML | Temps CPU (ms) | Scénario recommandé |
|---|---|---|---|
| 1 | 65 % | 2 | CPU limité |
| 4 | 72 % | 3 | Équilibré (recommandé) |
| 6 | 75 % | 5 | Bande passante limitée (recommandé) |
| 9 | 78 % | 12 | Cas extrêmes |
Les niveaux 4 et 6 conviennent dans la plupart des cas. Le niveau 9 double la charge CPU pour quelques points de compression en plus — peu rentable.
Configuration gzip complète que j’utilise en production :
# Configuration compression gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss
application/xhtml+xml
application/x-javascript;
gzip_disable "msie6";
gzip_proxied any est souvent oublié. En reverse proxy, si le backend ne renvoie pas Content-Length, la compression peut être ignorée ; any force la compression des réponses éligibles.
gzip_disable "msie6" contourne les bugs gzip d’IE6. Aujourd’hui IE6 a disparu ; la ligne peut partir, je la garde par habitude.
1.3 Quels types de fichiers profitent le plus ?
D’après nos mesures en production, l’effet varie fortement :
| Type | Taille originale | Après compression | Taux |
|---|---|---|---|
| HTML | 100 Ko | 20-25 Ko | 75-80 % |
| CSS | 80 Ko | 24-28 Ko | 65-70 % |
| JavaScript | 120 Ko | 36-42 Ko | 65-70 % |
| API JSON | 50 Ko | 20-25 Ko | 50-60 % |
| Image/vidéo | Déjà compressé | Peu utile | 0-5 % |
Images et vidéos (JPEG, PNG, MP4) sont déjà compressées ; gzip peut même grossir le fichier. Ne mettez pas image/* ni video/* dans gzip_types.
Une fois, en dépannage, gzip_types incluait image/jpeg : les images grossissaient de 3 à 5 %. Erreur classique — à mes débuts, j’avais tendance à tout lister.
Chapitre 2 : stratégie de cache — accélérer le contenu
Le cache est le levier le plus direct en tuning perf. Bien configuré, 95 % des requêtes peuvent être servies par Nginx sans toucher le backend. Trop de systèmes font tourner le backend à fond alors que le cache Nginx est quasi inutilisé — pas parce qu’il est off, mais mal réglé.
2.1 proxy_cache ou fastcgi_cache ?
Nginx propose deux mécanismes :
- proxy_cache : met en cache la réponse du serveur amont — reverse proxy (Node.js, Python, Go, etc.)
- fastcgi_cache : met en cache la réponse FastCGI — PHP-FPM
Choisissez selon la stack. PHP → fastcgi_cache ; Node, Python, Go → proxy_cache. La logique est quasi la même ; j’illustre avec proxy_cache.
2.2 Configuration complète de proxy_cache
D’abord, définir le chemin de cache dans le bloc http :
http {
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=my_cache:10m
max_size=10g
inactive=60m
use_temp_path=off;
}
Détail ligne par ligne :
levels=1:2: arborescence à deux niveaux, évite trop de fichiers dans un seul dossierkeys_zone=my_cache:10m: nom de zone et mémoire pour les métadonnées ; 10m ≈ 80 000 clésmax_size=10g: taille max du cache ; au-delà, éviction LRUinactive=60m: entrées non consultées depuis 60 min sont purgéesuse_temp_path=off: écriture directe dans le cache, sans fichier temporaire intermédiaire
Puis activation dans server ou location :
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Durées de validité
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;
# Clé de cache
proxy_cache_key $scheme$request_method$host$request_uri;
# Dégradation (voir plus bas)
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
# En-tête de debug
add_header X-Cache-Status $upstream_cache_status;
}
}
proxy_cache_valid fixe la durée par code HTTP :
200 302 10m: réponses OK mises en cache 10 minutes404 1m: 404 en cache 1 minute — limite les abus sur le backendany 1m: autres codes, 1 minute
2.3 Clé de cache et invalidation
proxy_cache_key définit ce qui compte comme « même » requête. Par défaut $scheme$proxy_host$request_uri ; je recommande d’expliciter :
proxy_cache_key $scheme$request_method$host$request_uri;
Protocole, méthode, hôte et URI complets — plus précis si GET/POST coexistent ou plusieurs domaines.
Invalidation : souvent pénible. Stratégies courantes :
- Expiration temporelle :
proxy_cache_valid - Contournement actif :
proxy_cache_bypass - Purge : Nginx Plus avec
proxy_cache_purge
J’utilise souvent le contournement via en-tête :
# Contournement via en-tête
proxy_cache_bypass $http_x_nocache;
# Ou via paramètre
proxy_cache_bypass $arg_nocache;
Pour rafraîchir : ?nocache=1 ou en-tête X-Nocache: 1.
2.4 Dégradation : servir même si le backend tombe
proxy_cache_use_stale est très utile : en erreur ou timeout backend, Nginx peut renvoyer une entrée expirée au lieu d’une erreur brute.
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
L’an dernier, pendant le 11.11, un problème de scale backend provoquait des 502 intermittents. Grâce à cette dégradation, l’accès utilisateur a peu souffert — contenu un peu daté mais disponible. Au retour du backend, le cache s’est mis à jour.
Comparaison mesurée :
| Indicateur | Sans cache | Cache HIT | Mode dégradé |
|---|---|---|---|
| Temps de réponse | 150-200 ms | 5-10 ms | 5-10 ms |
| QPS backend | 1000 | 50 | 0 |
| Expérience | Normale | Normale | Légèrement plus lent |
En hit cache, le temps passe de 200 ms à 5-10 ms — environ vingt fois plus rapide. Le gain est immédiat.
Chapitre 3 : pool de connexions — indispensable en haute concurrence
gzip et cache accélèrent le transfert ; le pool de connexions augmente la capacité. Par défaut, un worker Nginx plafonne à 1024 connexions — insuffisant dès que le trafic monte.
3.1 worker_connections : calculer le plafond
Formule :
Concurrence max = worker_processes × worker_connections
Serveur 8 cœurs, worker_processes à 8 (ou auto), worker_connections à 4096 :
Concurrence max = 8 × 4096 = 32768
Chiffre élevé, mais une requête utilise souvent deux connexions (client → Nginx, Nginx → backend). La concurrence utile est environ la moitié.
Configuration dans le bloc events :
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
use epoll est le défaut sous Linux ; l’écrire explicite la doc. multi_accept on accepte plusieurs connexions d’un coup — moins de file d’attente en pic.
3.2 keepalive client : réutiliser les connexions
Établir une connexion TCP coûte cher (three-way handshake). keepalive réutilise le lien client ↔ Nginx.
http {
keepalive_timeout 65;
keepalive_requests 1000;
}
keepalive_timeout 65 : connexion maintenue 65 s. Trop long → ressources occupées ; trop court → peu de réutilisation. 60-75 s est un bon intervalle.
keepalive_requests 1000 : max 1000 requêtes par connexion. Trop bas → coupures fréquentes ; trop haut → risque de fuite. 1000 est un bon compromis en pratique.
3.3 upstream keepalive : pool côté backend
Peu connu, très efficace : Nginx peut aussi réutiliser les connexions vers le backend.
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
keepalive 64;
keepalive_timeout 60s;
keepalive_requests 1000;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
keepalive 64 : pool de 64 connexions idle — à ajuster (souvent 4-8× le nombre de serveurs backend).
proxy_http_version 1.1 et proxy_set_header Connection "" sont obligatoires. Sans eux, upstream keepalive ne fonctionne pas.
Comparaison mesurée :
| Config | Connexions/min | Charge CPU | Scénario |
|---|---|---|---|
| Sans upstream keepalive | 6000 | Élevée | Faible trafic |
| keepalive 32 | 3000 | Moyenne | Trafic moyen |
| keepalive 64 | 1500 | Faible | Fort trafic |
upstream keepalive divise environ par deux le coût d’établissement des connexions — crucial en haute concurrence.
3.4 Tableau de paramètres recommandés
Réglages de départ par scénario :
| Paramètre | Faible trafic (<1000 QPS) | Moyen (1000-5000 QPS) | Élevé (>5000 QPS) |
|---|---|---|---|
| worker_processes | auto | auto | auto |
| worker_connections | 1024 | 2048 | 4096 |
| keepalive_timeout | 60 | 65 | 75 |
| keepalive_requests | 100 | 500 | 1000 |
| upstream keepalive | 16 | 32 | 64 |
Point de départ seulement — validez au bench. J’utilise wrk ou ab, courbes connexions / latence, puis j’affine.
Chapitre 4 : modèle de configuration — prêt pour la production
Les trois chapitres précédents posent le fond ; voici un template intégré. Adaptez les valeurs, la structure reste générique.
# nginx.conf — modèle production
user nginx;
worker_processes auto;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml
application/xml+rss application/xhtml+xml;
gzip_disable "msie6";
# Cache
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=my_cache:10m
max_size=10g
inactive=60m
use_temp_path=off;
# Connexions client
keepalive_timeout 65;
keepalive_requests 1000;
# Upstream
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
keepalive 64;
keepalive_timeout 60s;
keepalive_requests 1000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Cache
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_key $scheme$request_method$host$request_uri;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
}
}
}
Trois profils métier
E-commerce : accueil et fiches produit changent souvent — cache 10-15 min. upstream keepalive élevé : requêtes lourdes côté base.
API : fraîcheur des données — proxy_cache_valid souvent 1-5 min. gzip très utile sur JSON.
Site statique : HTML/CSS/JS stables — cache 1 h ou plus. gzip maximal sur le texte.
Chapitre 5 : problèmes fréquents et dépannage
Quelques cas que j’ai souvent vus, avec la marche à suivre.
Q : gzip inactif, pas de Content-Encoding: gzip
Vérifier :
gzip ondans le bon bloc (http)gzip_typesinclut le MIME de la réponse- Taille ≥
gzip_min_length
Test : curl -H "Accept-Encoding: gzip" -I http://your-site.com
Q : faible taux de hits, X-Cache-Status surtout MISS
Causes fréquentes :
- Clé de cache trop variable — chaque requête « unique »
proxy_cache_validtrop court- Backend avec
Cache-Control: no-cacheouSet-Cookie
Inspectez les en-têtes de réponse.
Q : worker_connections insuffisant, erreurs 502
Dans les logs : worker_connections are not enough → concurrence au-delà du plafond.
Actions :
- Augmenter
worker_connections - Chercher une fuite de connexions (keepalive mal réglé)
- Ajouter des nœuds et équilibrer la charge
Q : mémoire haute, OOM fréquent
Pistes :
keys_zonedeproxy_cache_pathtrop grand- Trop de fichiers cache, mmap lourd
- Pool keepalive trop large
Réduisez ces paramètres ou ajoutez de la RAM.
Pour conclure
Les trois piliers du tuning Nginx : gzip, cache, pool de connexions. Bien combinés, ils peuvent doubler la vitesse perçue et multiplier la concurrence par trois ou quatre.
Le tuning n’est pas un one-shot. Ordre que je recommande :
- gzip d’abord : changement minimal, gain immédiat — dix minutes
- cache ensuite : stratégie selon le métier — une journée
- pool en dernier : bench requis — quand le trafic est stable
Après chaque changement, bench (wrk, ab) : latence, QPS, taux d’erreur. Pas au feeling — aux chiffres.
Checklist finale :
- gzip activé, types MIME complets
- gzip_comp_level entre 4 et 6
- proxy_cache_path configuré, taille cohérente
- proxy_cache_valid adapté au métier
- proxy_cache_use_stale pour la dégradation
- worker_connections ≥ 4096
- keepalive_timeout 60-75 s
- upstream keepalive + HTTP/1.1 + en-tête Connection
- X-Cache-Status pour le debug
Voilà l’essentiel. Questions en commentaire — j’essaierai de répondre.
Processus de réglage des performances Nginx
Trois étapes pour configurer gzip, cache et pool de connexions en production
⏱️ Estimated time: 30 min
- 1
Step 1: Activer la compression gzip
Ajoutez dans le bloc http :
• gzip on; — activer la compression
• gzip_vary on; — ajouter l'en-tête Vary
• gzip_comp_level 6; — niveau de compression (4-6 recommandé)
• gzip_min_length 1000; — ne pas compresser sous 1 Ko
• gzip_types — types MIME : text/plain text/css application/json application/javascript - 2
Step 2: Configurer le cache proxy_cache
En deux étapes :
Étape 1 — définir le chemin de cache
• proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
Étape 2 — activer le cache dans location
• proxy_cache my_cache;
• proxy_cache_valid 200 10m; — cache 10 min pour les réponses 200
• proxy_cache_use_stale error timeout http_502; — stratégie de dégradation - 3
Step 3: Optimiser les paramètres du pool de connexions
Trois réglages clés :
• worker_connections 4096; — dans le bloc events
• keepalive_timeout 65; keepalive_requests 1000; — dans le bloc http
• upstream keepalive 64; proxy_http_version 1.1; proxy_set_header Connection ""; — pool de connexions backend
FAQ
Quel niveau de compression gzip choisir ?
proxy_cache ou fastcgi_cache : lequel choisir ?
Quelle valeur pour worker_connections ?
Comment diagnostiquer un faible taux de hits du cache ?
Pourquoi upstream keepalive exige HTTP/1.1 ?
Comment ajuster la durée de cache selon le métier ?
10 min de lecture · Publié le: 11 avr. 2026 · Mis à jour le: 27 juil. 2026
Guide pratique Nginx
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Guide complet du reverse proxy Nginx : upstream, mise en tampon et timeouts
Analyse approfondie des trois piliers du reverse proxy Nginx : équilibrage upstream, réglage des proxy buffers et timeouts, avec dépannage 502/504, pool keepalive et contrôles de santé.
Partie 1 sur 6
Suivant
Configuration Nginx SSL/TLS en pratique : du certificat HTTPS au durcissement A+
Configurer Nginx HTTPS de zéro : certificat Let's Encrypt, durcissement TLS 1.3, modèle A+ SSL Labs, optimisation OCSP Stapling — guide complet à jour pour 2026.
Partie 3 sur 6



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire