...

Optimisation des requêtes Keepalive NGINX : des performances optimales pour le serveur web grâce à un réglage ciblé

Avec nginx keepalive Je réduis les coûts d'établissement de connexion, je limite les échanges de données d'initialisation et j'accélère sensiblement les temps de réponse. Des délais d'expiration adaptés de manière ciblée, des limites de requêtes par connexion et la réutilisation des sockets en amont permettent d'obtenir des gains de performances mesurables sans avoir recours à du nouveau matériel.

Points centraux

  • Timeouts Choisir judicieusement : un temps d'inactivité aussi court que nécessaire, aussi long que utile.
  • Requêtes Limiter par connexion : sockets durables, pas de blocages.
  • Pools en amont Activer : connexions persistantes au backend par worker.
  • Travailleur et ajuster les connexions : suffisamment d'emplacements pour les clients inactifs et actifs.
  • Suivi Mettre en place : surveiller le taux de connexion, la latence et les erreurs.

NGINX Keepalive : impact et coûts

Je laisse délibérément les connexions TCP ouvertes, car Poignées de main sont coûteuses et prédominent dans de nombreuses petites requêtes. Les sockets persistants permettent non seulement de réduire les temps de transit (RTT), mais aussi de lisser la charge du processeur, car les opérations cryptographiques liées au protocole TLS sont moins fréquentes. Chaque connexion ouverte occupe toutefois Ressources, comme les descripteurs de fichiers et les tampons, que je dois surveiller de près. Tout est une question d'équilibre : suffisamment de réutilisation pour garantir la vitesse, suffisamment de ressources pour établir de nouvelles connexions lors des pics de charge. En trouvant le bon équilibre, on obtient des valeurs TTFB constamment faibles et une expérience utilisateur fluide.

HTTP/2 et HTTP/3 : le multiplexage associé au keep-alive

Avec HTTP/2 et HTTP/3 le nombre de connexions nécessaires par client diminue, car plusieurs flux transitent par une seule ligne. Le « keepalive » reste néanmoins important : une connexion doit rester ouverte de manière fiable, sinon l'avantage du multiplexage est réduit à néant par les reconnexions fréquentes.

Je veille à définir des paramètres d'inactivité spécifiques aux protocoles modernes et je m'assure que ces valeurs correspondent aux délais d'expiration de mes clients. Pour les tests, je commence par des valeurs modérées, puis je les augmente lorsque la charge est stable, jusqu'à ce que le taux de reconnexion diminue et que les latences restent constantes.

http {
    # HTTP/2 : délai d'inactivité pour les flux inactifs mais ouverts
    http2_idle_timeout 60s;

    # HTTP/3/QUIC : logique similaire pour les connexions basées sur UDP
    http3_idle_timeout 60s;

    # La reprise TLS réduit les coûts liés à la négociation lors des nouvelles connexions
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
}

Le multiplexage réduit le nombre de connexions TCP/QUIC parallèles nécessaires, mais pas l'importance de la les délais d'attente corrects. Les utilisateurs de HTTP/2/3 peuvent souvent définir des délais d'expiration côté client un peu plus longs, car de nombreuses petites ressources transitent par le même canal. Important : rester mesurable Temps au premier octet, taux d'erreur et flux ouverts par connexion.

Configurer correctement le « client keepalive »

Pour les clients navigateur, je gère la réutilisation via keepalive_timeout et keepalive_requests, afin que les sockets restent actifs suffisamment longtemps sans rester bloqués indéfiniment. Je commence par définir un délai d'expiration de 30 à 60 secondes et 100 à 300 requêtes par connexion, puis j'ajuste ces valeurs en fonction des métriques. Vous trouverez des informations détaillées à ce sujet dans cet article Guide sur le délai d'expiration des requêtes Keepalive, qui explique les répercussions sur la latence et les ressources du serveur. Des délais d'expiration plus courts conviennent en cas de très nombreux appels courts, tandis que des délais plus longs sont préférables pour les accès périodiques à l'API. Pour commencer, je définis des valeurs par défaut claires et j'évalue leur impact sur les connexions ouvertes ainsi que sur les types d'erreurs.

http {
    # Connexions inactives vers le client
    keepalive_timeout 60s;
    # Limite maximale de requêtes par connexion TCP
    keepalive_requests 200;

    # Facultatif : désactiver le Keep-Alive pour certains clients (bugs hérités)
    # keepalive_disable msie6;
}

Keepalive en amont dans le proxy inverse

Entre NGINX et les applications backend, j'utilise des sockets upstream persistants, car la connexion à PHP-FPM, Node.js ou aux services Python se fait également Latence coûte. Pour cela, j’active dans le pool en amont un nombre adapté de connexions réutilisables par worker. Il est important d’utiliser HTTP/1.1 en aval et un en-tête „ Connection “ vide, sinon la requête « close » du client rompt la persistance du backend. Je me base sur le nombre de requêtes simultanées et configure le pool de manière à ce qu’il n’y ait pratiquement pas de nouvelles connexions. Cela réduit le temps de connexion au backend, et l’ensemble de la chaîne offre des performances plus rapides Réponses.

upstream backend {
    server 127.0.0.1:9000;
    keepalive 64; # Nombre de connexions en amont persistantes par worker
}

server {
    location / {
 proxy_pass http://backend;
        proxy_http_version 1.1;
 proxy_set_header Connection "";
 # Keepalive TCP pour les sockets en amont au niveau du système d'exploitation
 proxy_socket_keepalive on;
    }
}

Dimensionnement du pool et budget de connexion

Je calcule les pools de manière réaliste : le nombre de connexions en amont persistantes résulte de worker_processes × keepalive par serveur en amont. Si vous utilisez 8 workers et une valeur keepalive de 64, vous maintenez jusqu'à 512 sockets ouverts par serveur en amont – par instance. Derrière un équilibreur de charge ou en présence de plusieurs serveurs en amont, cela peut rapidement faire beaucoup.

Mon objectif : disposer d'un nombre suffisant de sockets ouverts pour que la majeure partie des requêtes sans nouveau Connect est satisfait, mais qu'il reste encore une marge pour les pics. Je surveille la métrique „ nouvelles connexions en amont par seconde “ et je la réduis jusqu'à ce que les augmentations supplémentaires de la taille du pool n'apportent plus d'amélioration notable en termes de latence.

Je tiens également compte Équité: Des pools trop importants peuvent pénaliser les clients qui viennent d'arriver, car les slots des workers sont occupés par des connexions inactives. Une limite modérée associée à une surveillance active s'avère généralement plus efficace que des valeurs maximales fixées à l'aveuglette.

Réglage précis : délais d'expiration et limites de requêtes

Je combine le délai d'expiration et la limite de requêtes de manière à ce que les connexions soient effectivement réutilisées, sans pour autant Ski de fond . Des valeurs élevées sur les deux axes réduisent le nombre de connexions, mais augmentent le risque de sockets bloqués en cas de problèmes réseau. Des valeurs faibles garantissent des connexions fraîches, mais nécessitent des handshakes supplémentaires. J’avance par petites étapes, j’observe les erreurs et j’ajuste à intervalles réguliers. Le tableau suivant présente des plages de valeurs de départ pertinentes pour différents modèles d’utilisation et fournit un aperçu concis Orientation.

Scénario keepalive_timeout keepalive_requests Remarque
De nombreuses consultations de pages courtes 10 à 30 s 100-300 Réutilisation rapide, faible occupation en veille
Site web type 60 à 120 s 200–400 Un bon compromis pour les ressources et le HTML
API avec des appels périodiques 60 à 120 s 300–1000 Taux de réutilisation plus élevé pour les clients
Services internes / Passerelles 30 à 90 s 500–1000+ La constance prime sur un nombre minimal de connexions

Optimisation des workers et connexions

Je pose worker_processes sur « auto » ou sur le nombre de cœurs du processeur, et prévoir suffisamment worker_connections car les sockets inactives occupent des emplacements. Des limites trop basses empêchent l'acceptation de nouvelles connexions, même s'il reste de la capacité CPU disponible. Ceux qui utilisent des pools de keepalive importants ont besoin d'un nombre suffisant de descripteurs et d'emplacements d'événements par worker. On trouvera une bonne introduction dans „Faire évoluer les connexions des travailleurs“, qui explique les liens entre les événements, les connexions et la charge. Des valeurs bien pensées garantissent que la réutilisation en mode veille et les reconnexions puissent coexister.

worker_processes auto;

events {
    worker_connections 4096;
    # Facultatif : l'option « reuseport » peut améliorer la répartition au niveau du noyau
    # multi_accept on;
}

http {
    keepalive_timeout 60s;
    keepalive_requests 200;

 upstream backend {
 server 127.0.0.1:9000;
 keepalive 64;
    }
}

Optimisation du système d'exploitation et des sockets

Je vérifie les limites du système afin que Keepalive puisse exploiter pleinement son potentiel. Un nombre insuffisant de descripteurs ou des files d'attente de sockets trop courtes entraînent goulets d'étranglement artificiels. Outre les paramètres « ulimit » et « worker_rlimit_nofile », les limites du noyau jouent un rôle déterminant.

# Exemples de valeurs sysctl (à ajuster avec prudence et après avoir effectué des tests)
fs.file-max = 1000000
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 16384
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_syn_backlog = 262144

J'ajuste ces valeurs en fonction de l'environnement : de nombreuses connexions de courte durée bénéficient d'une plage de ports plus large et de temps FIN/TIME_WAIT plus courts. Pour le keepalive en amont, je réduis Neuconnects, ce qui réduit les pics de TIME_WAIT. De plus, je tiens compte NAT- Appareils situés entre le proxy et le backend : des délais d'inactivité trop stricts sur le réseau peuvent interrompre les connexions de manière imprévisible. Une limite modérée de requêtes par socket et l'utilisation des keepalives TCP (proxy_socket_keepalive on ;) permettent d'éviter les connexions „ obsolètes “.

Définir correctement l'en-tête et la version HTTP

Je fais attention à HTTP/1.1 vers le backend, car Upstream-Keepalive ne fonctionne qu’ainsi. De plus, je supprime la gestion active des connexions via les en-têtes afin que NGINX gère lui-même la persistance. Côté client, je laisse Keep-Alive fonctionner conformément à la norme et je limite sa durée de vie via le délai d’expiration et la limite de requêtes. De plus, je vérifie les délais d’inactivité du backend et je les règle à une valeur légèrement supérieure à celle de NGINX afin d’éviter les erreurs de réinitialisation. Des en-têtes bien formés garantissent la Réutilisation sans fermetures involontaires.

Exemple # : emplacement proxy avec des en-têtes corrects
location /api/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
}

Différence entre HTTP Keep-Alive et TCP Keep-Alive

Je fais une distinction stricte entre HTTP Keep-Alive (plusieurs requêtes HTTP par connexion) et TCP-Keepalive (Tests au niveau du système d'exploitation pour détecter les terminaux inactifs). Je contrôle la fonctionnalité HTTP Keep-Alive à l'aide de keepalive_timeout et keepalive_requests, tandis que les « keepalives » TCP, selon la pile, peuvent durer proxy_socket_keepalive on ; et les paramètres système. Pour les backends utilisant des réseaux instables, j'active les keepalives TCP afin de libérer plus rapidement les sockets bloquées.

Applications de longue durée et cas particuliers : WebSockets, SSE, gRPC

Les WebSockets et les Server-Sent Events sont Ski de fond, qui maintiennent une connexion ouverte pendant une longue période – dans ce cas, le modèle Reuse classique joue un rôle secondaire. Je m'assure de trouver des proxy_read_timeout et protège-moi avec send_timeout contre Slowloris-Effets. Pour gRPC (basé sur HTTP/2), les considérations relatives au multiplexage s'appliquent ; je configure les délais d'inactivité de manière à ce que les flux ne soient pas interrompus inutilement.

location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 300s;
    send_timeout 30s;
}

Suivi et métriques

Je mesure le succès à l'aide d'indicateurs tels que le taux de nouvelles connexions en amont, upstream_connect_time et la proportion de connexions ouvertes par worker. Une baisse des taux de connexion alors que le nombre de requêtes reste stable ou augmente indique une réutilisation réussie. Des délais d'expiration ou des réinitialisations de connexion inhabituels signalent des délais d'expiration incohérents entre NGINX et le backend. De plus, je surveille la mémoire, les descripteurs de fichiers et les files d’attente d’événements sous charge. En effectuant des contrôles réguliers, on détecte les tendances à un stade précoce et on évite des Pannes.

Améliorations de la journalisation pour une meilleure transparence de la réutilisation

Pour avoir une meilleure vue d'ensemble, j'ajoute des détails sur les connexions au journal d'accès. Cela me permet de voir à quelle fréquence une connexion TCP est réutilisée et comment évoluent les temps de connexion.

log_format keepalive_fmt
  '$remote_addr $host "$request" $status $body_bytes_sent '
  '$request_time $upstream_connect_time '
  'conn:$connection reqs:$connection_requests' ;

access_log /var/log/nginx/access_keepalive.log keepalive_fmt ;

J'observe les valeurs médianes et P95/P99 de upstream_connect_time ainsi que la répartition de $_demandes_de_connexion. Une augmentation du nombre de requêtes réutilisées alors que la latence reste stable indique que les pools et les délais d'expiration ont été choisis de manière appropriée.

Points d'achoppement typiques et solutions

Les pools trop volumineux saturent les slots de connexion, tandis que les nouveaux clients restent en attente ; c'est pourquoi je veille à ce que leur taille reste modérée et je les surveille. Des délais d'inactivité différents entre le proxy et le backend provoquent des réinitialisations ; je règle donc le délai du backend à une valeur légèrement supérieure à NGINX. Un „ Connection: close “ oublié dans l'en-tête du proxy interrompt la persistance ; c'est pourquoi je vide systématiquement cet en-tête. La négociation TLS peut solliciter fortement le processeur en cas de nombreuses nouvelles connexions, ce que j'atténue en augmentant le taux de réutilisation. En cas de pannes réseau sporadiques, une limite modérée du nombre de requêtes par socket permet de s’assurer que les anciennes Sessions ne vivront pas éternellement.

Configurations adaptées à la pratique

Pour les sites web très fréquentés, je choisis un délai d’expiration court et une limite de requêtes modérément élevée afin que les ressources fonctionnent efficacement. Pour les API avec des appels récurrents, j’augmente la limite afin de réduire davantage les poignées de main TCP et TLS. Je dimensionne les pools en amont en fonction du parallélisme attendu et je les teste avec un trafic réaliste. Chaque environnement se comportant différemment, je vérifie la latence et les profils d'erreurs après chaque modification. Voici deux exemples : valeurs initiales, que j'affine ensuite à l'aide d'indicateurs.

Scénario # : site web très fréquenté
http {
    keepalive_timeout 30s;
    keepalive_requests 300;

 upstream app {
 server 127.0.0.1:8080;
        keepalive 32;
    }

 server {
 listen 443 ssl http2;
 Surveiller le temps d'inactivité HTTP/2 (#)
 http2_idle_timeout 45s;
    }
}
# Scénario 2 : API avec appels périodiques
http {
    keepalive_timeout 75s;
    keepalive_requests 1000;

    upstream api_backend {
    server 127.0.0.1:9001;
    keepalive 64;
    }

    server {
 listen 443 ssl http2;
 # Fenêtre d'inactivité légèrement plus longue pour les appels récurrents
 http2_idle_timeout 75s;
    }
}

Liste de contrôle pour l'optimisation itérative

Je commence par analyser la situation actuelle : les modèles de trafic, les temps de réponse et le taux d'erreur donnent le ton. Ensuite, je définis le délai d'expiration client et la limite de requêtes sur des valeurs de départ raisonnables, puis j'active les pools en amont. Je règle les délais d'expiration en cas d'inactivité du backend à une valeur légèrement supérieure à celle de NGINX, afin d'éviter toute réinitialisations apparaissent. Je surveille ensuite les taux de connexion, le temps de connexion et le nombre de sockets ouverts par worker. Si vous souhaitez approfondir la question du taux de réutilisation, vous trouverez des suggestions concernant Réutilisation de la connexion et des plafonds raisonnables.

Diagnostic complémentaire : décalages et comportement temporel

Lorsque les connexions semblent se couper „ sans raison “, je cherche Incohérences dans la chaîne : inactivité du client vs. délai d'expiration NGINX vs. inactivité du backend et NAT/passerelles intermédiaires. J'augmente légèrement le délai d'expiration du backend au-delà de la valeur NGINX, je vérifie les codes de réinitialisation dans le journal d'erreurs et j'observe si upstream_connect_time présente des pics. Souvent, une petite marge (par exemple +10–20%) au niveau du délai d'attente du backend suffit pour éliminer les réinitialisations.

Je note également que „un baiser prolongé“ Phases de fermeture : lors de la fermeture, NGINX laisse les données entrantes s'écouler brièvement, ce qui mobilise les ressources des workers. Un très grand nombre de fermetures simultanées peut bloquer les événements. Dans de tels cas, je calibre les fenêtres de fermeture et je maintiens le nombre total de connexions ouvertes à un niveau raisonnable en définissant des valeurs de keepalive appropriées. ».

Résumé : Le « keepalive » comme levier de performance

J'utilise Keepalive de manière ciblée, car cela réduit les coûts d'établissement de connexion, diminue la latence et soulage le processeur. La combinaison d'un délai d'expiration adapté, d'une limite de requêtes bien définie et de pools en amont adaptés apporte des avantages notables Vitesse. Sans suivi, le potentiel reste inexploité ; c'est pourquoi je vérifie en permanence les indicateurs clés et j'ajuste les valeurs étape par étape. Si vous avez besoin de ressources supplémentaires, veillez au nombre de workers, aux slots de connexion et au traitement correct des en-têtes. Les configurations professionnelles, par exemple chez webhoster.de, exploitent pleinement ces leviers et fournissent des services rapides et fiables.

Derniers articles

Serveur web NGINX avec des connexions Keepalive optimisées dans un centre de données moderne
Serveur web Plesk

Optimisation des requêtes Keepalive NGINX : des performances optimales pour le serveur web grâce à un réglage ciblé

Découvrez comment optimiser les requêtes Keepalive de NGINX afin d'améliorer considérablement les performances de vos serveurs web. Grâce à des réglages concrets pour les paramètres keepalive_timeout, keepalive_requests, Upstream-Keepalive et le réglage des workers – avec un accent particulier sur le Keepalive de NGINX en tant que paramètre clé.