...

Keep Alive Webserver : configurer correctement le frein silencieux des performances

Le serveur web Keep Alive détermine souvent le temps d'attente ou la vitesse : mal réglé, il ralentit silencieusement, correctement réglé, il accélère sensiblement chaque requête. Je montre concrètement comment je Keep-Alive Configurez les plages horaires qui fonctionnent et pourquoi les plages ouvertes trop longues TCPLes connexions coûtent de la puissance.

Points centraux

  • mécanisme: Les connexions TCP ouvertes permettent d'économiser des handshakes et de réduire la latence.
  • valeurs fondamentales: sélectionner KeepAliveTimeout, MaxKeepAliveRequests et l'activation de manière ciblée.
  • Charge du serveur: Des plages horaires correctement réglées réduisent les besoins en CPU et en RAM.
  • Cabinet médical: tenir compte systématiquement du comportement du navigateur et des chaînes de proxy inverse.
  • Contrôle: Mesurer, ajuster, mesurer à nouveau – jusqu'à ce que le point idéal soit atteint.

Ce que fait Keep Alive

Au lieu de commencer chaque requête par une nouvelle poignée de main, Keep-Alive maintient la TCP-Connexion ouverte et traite plusieurs requêtes via celle-ci. Dans un scénario avec 50 requêtes par seconde provenant de trois clients, le flux de paquets diminue considérablement : d'environ 9 000 à environ 540 paquets par minute, car moins de connexions sont établies et moins de poignées de main sont effectuées. Cela réduit les temps d'attente et économise des cycles serveur, ce qui a des effets directs sur Temps de chargement et débit. Lors des tests, le temps est réduit de moitié, passant d'environ 1 190 ms à environ 588 ms, soit une baisse de plus de 50 %, à condition que le reste de la chaîne ne soit pas limité. C'est pourquoi j'ancrage toujours Keep-Alive dès le début de la configuration et je contrôle les latences réelles dans le trafic en direct.

Les bons indicateurs

Je commence par les trois paramètres qui ont toujours un effet : l'activation, le nombre de requêtes par connexion et le délai avant la fermeture de la Connexion. L'activation détermine si la réutilisation a lieu ou non ; le nombre maximal de requêtes contrôle la durée pendant laquelle une connexion reste ouverte ; le délai d'expiration équilibre l'économie et la réactivité. Une fenêtre temporelle trop grande bloque les slots et gaspille de la RAM, car les sockets inactifs restent en place et les workers manquent. Une fenêtre trop courte annule les avantages, car le serveur se déconnecte trop tôt et doit redémarrer. Je m'en tiens à des valeurs par défaut modestes et ne les augmente que lorsque les mesures confirment de réels temps d'attente en mode veille.

HTTP/1.1 vs HTTP/2/3 : classification

Keep-Alive fonctionne par connexion TCP. Avec HTTP/1.1, plusieurs requêtes se partagent une ligne les unes après les autres, avec HTTP/2, plusieurs flux multiplexés via une seule connexion, HTTP/3 utilise QUIC au lieu de TCP. Voici mon avis à ce sujet : un délai d'expiration court reste utile même avec HTTP/2, car les flux inactifs ont un coût – la connexion continue de consommer des ressources, en particulier dans le cas de TLS. Nginx dispose de sa propre fenêtre d'inactivité pour HTTP/2 ; je veille à ce que les valeurs globales Keep-Alive et les valeurs limites spécifiques à HTTP/2 correspondent entre elles et ne soient pas trop élevées. Important : Nginx ne communique actuellement qu'avec le client HTTP/2 ; il maintient le backend HTTP/1.1ouvertes. Upstream-Keepalive reste donc obligatoire afin de conserver l'avantage de bout en bout. Des principes similaires s'appliquent à HTTP/3 : même si QUIC masque mieux les pertes, un canal ouvert depuis longtemps et inutilisé coûte de la mémoire et des descripteurs de fichiers. Mon approche reste donc conservatrice : fenêtres d'inactivité courtes, limites claires, et mieux vaut une reconnexion propre qu'une attente sans fin.

Considération pragmatique de la surcharge TLS

TLS augmente encore davantage les économies réalisées grâce à Keep-Alive, car les handshakes sont plus coûteux que les simples constructions TCP. Avec TLS 1.3 et Session-Resumption, la charge diminue, mais au final, chaque nouvelle connexion évitée est un gain. Je vérifie trois points dans la pratique : premièrement, si le serveur utilise correctement la reprise de session (ne pas laisser les tickets expirer trop tôt). Deuxièmement, si des chiffrements puissants et des protocoles modernes sont actifs sans forcer inutilement les anciens clients. Troisièmement, si l'utilisation du CPU reste stable en cas de parallélisme élevé. Même avec la reprise, des fenêtres de keep-alive courtes et stables évitent des pics supplémentaires du CPU, car moins de négociations sont lancées. En même temps, avec des fenêtres trop longues, je n'empêche pas les poignées de main, mais je déplace la charge vers l'inactivité, ce qui est la variante la plus coûteuse.

Apache : paramètres recommandés

Avec Apache, j'active KeepAlive sur On, définissez MaxKeepAliveRequests sur 300-500 et sélectionnez généralement une fenêtre temporelle de 2-3 secondes. La valeur 0 pour le nombre maximal de requêtes semble tentante, mais une valeur illimitée est rarement judicieuse, car les connexions durent alors trop longtemps. coller. Pour les applications très fréquentées avec des clients stables, je teste 5 à 10 secondes ; en cas de pics avec de nombreuses visites courtes, je descends à 1 à 2 secondes. Il est important de commencer par réduire le délai d'expiration, puis d'ajuster plus précisément le nombre de requêtes afin que les slots ne soient pas bloqués par l'inactivité. Si vous n'avez pas accès à la configuration principale, vous pouvez contrôler le comportement de connexion par répertoire via mod_headers, à condition que l'hébergeur ait activé cette option.

Nginx : réglage judicieux

Sous Nginx, Keep-Alive est activé par défaut, c'est pourquoi je prête particulièrement attention au délai d'expiration, aux exceptions du navigateur et au nombre par connexion. Avec keepalive_timeout, je définis le nombre de secondes ouvertes, que j'ajuste progressivement de 1 à 5 secondes en fonction du modèle de trafic ; en cas d'appels API nombreux, 10 secondes peuvent également être judicieuses. Avec keepalive_disable, j'exclue les anciens clients problématiques afin qu'ils ne puissent pas Sessions . Pour les proxys inversés vers les flux ascendants, j'utilise également upstream keepalive afin que Nginx réutilise les connexions vers le backend et y lie moins de workers. Je maintiens ainsi la cohérence du chemin de bout en bout et empêche les séparations au milieu du flux de requêtes.

Proxy inverse et transfert d'en-tête

Dans les configurations à plusieurs niveaux, j'ai besoin d'une Stratégie, qui transmet correctement les en-têtes HTTP/1.1 et ne remplace pas accidentellement les valeurs de connexion. Nginx doit communiquer en HTTP/1.1 avec le backend et tolérer explicitement Keep-Alive, tandis qu'Apache utilise les fenêtres temporelles appropriées en arrière-plan. Les configurations qui forcent Connection: close ou perturbent les chemins de mise à niveau sont critiques, car elles annulent le gain supposé. Sous Apache, je peux contrôler via mod_headers pour chaque emplacement si les connexions restent ouvertes et quelles informations supplémentaires sont définies. Tous les nœuds doivent poursuivre le même objectif, sinon un maillon crée la effet de freinage, que je voulais justement éviter.

CDN, équilibreurs de charge et configurations cloud

Si un CDN ou un équilibreur de charge est installé en amont, la plupart des connexions client aboutissent là. L'origine bénéficie alors principalement de connexions permanentes et peu nombreuses entre la périphérie et l'origine. Je veille à ce que l'équilibreur fonctionne également avec des fenêtres d'inactivité courtes et que le regroupement de connexions vers le backend soit activé. Dans les environnements conteneurisés et cloud, le flux de vidange est également important : avant une mise à jour progressive, j'envoie le nœud dans le Drainage-Status, je laisse les connexions ouvertes expirer rapidement (délai d'attente pas trop long) et je ne lance le remplacement qu'ensuite. Cela me permet d'éviter les requêtes interrompues et les connexions zombies restantes. Les sessions persistantes (par exemple via des cookies) peuvent fragmenter les pools de connexions ; dans la mesure du possible, je mise sur des connexions à faible état. back-ends ou des magasins de sessions externes afin que la réutilisation s'applique de manière uniforme.

Vitesse d'hébergement dans la pratique

De nombreux environnements partagés désactivent Keep-Alive afin de Slots économiser, mais les pages deviennent lentes et perdent leur interactivité. Je vérifie donc dès le début, à l'aide de tests de temps de chargement, si le serveur autorise la réutilisation et à quoi ressemblent les phases de connexion dans le diagramme en cascade. Si l'outil détecte de longs blocs de handshake entre de nombreux petits actifs, cela signifie généralement que la réutilisation fait défaut ou que le délai d'attente se termine trop tôt. Pour affiner les réglages, je m'aide d'un guide structuré tel que ce guide compact. Réglage Keep Alive, afin que je puisse effectuer les étapes proprement. Cela m'évite d'avoir à deviner et me permet d'obtenir un résultat tangible en quelques gestes seulement. élan à l'avant.

Délais d'attente, limites et comportement du navigateur

Les navigateurs modernes ouvrent plusieurs fenêtres parallèles par hôte. Connexions, souvent six, et épuisent ainsi rapidement la capacité Keep-Alive. Un MaxKeepAliveRequests de 300 suffit dans la pratique pour de nombreux visiteurs simultanés, à condition que le délai d'expiration ne soit pas inutilement élevé. Si je règle la fenêtre sur trois secondes, des emplacements restent disponibles et le serveur donne la priorité aux clients actifs plutôt qu'à l'inactivité. Ce n'est que lorsque les requêtes s'interrompent régulièrement ou que la réutilisation ne fonctionne pas que j'augmente la limite par paliers modérés. Les pages comportant de nombreux flux HTTP/2 doivent être considérées séparément. Les détails sont résumés dans Multiplexage HTTP/2 très compact, afin que je puisse classer proprement l'utilisation des canaux et le keep-alive.

Paramètres Directive Apache Directive Nginx valeur indicative Remarque
Activation KeepAlive activé actif par défaut Toujours activer Sans réutilisation, cela augmente Overhead.
Délai d'attente KeepAliveTimeout keepalive_timeout 2 à 5 s Plus court pour de nombreux appels courts, plus long pour APIs.
Nombre/Conn MaxKeepAliveRequests keepalive_requests 300–500 Limite l'engagement des ressources par Client.
Exceptions du navigateur - keepalive_disable sélectif Désactiver pour les très anciens Clients.
en amont ProxyKeepAlive maintien de connexion en amont actif Assure la réutilisation Direction Backend.

Limites du système d'exploitation et sockets

Au niveau du système d'exploitation, les descripteurs de fichiers et les paramètres de socket limitent la capacité réelle. Je vérifie ulimit -n, les limites du processus et du système, ainsi que la configuration du serveur web (par exemple worker_connections chez Nginx). Keep-Alive réduit certes le nombre de nouvelles connexions, mais augmente la durée pendant laquelle les descripteurs restent occupés. Pendant les périodes de forte fréquentation, une pression TIME_WAIT peut apparaître lorsque les connexions se ferment très rapidement. Dans ce cas, une réutilisation propre est préférable à des hacks agressifs du noyau. Je fais une distinction claire entre HTTP-Keep-Alive (protocole d'application) et les sondes TCP Keepalive du noyau : ces dernières sont de simples paquets de signes de vie, à ne pas confondre avec la fenêtre HTTP ouverte. Je ne modifie les paramètres par défaut du noyau qu'avec un point de mesure et j'interviens en priorité sur le serveur web lui-même : des délais d'inactivité courts mais efficaces, un nombre limité de requêtes par connexion et des réserves de travail raisonnables.

Sécurité : désamorcer Slowloris & Co.

Des valeurs Keep-Alive trop généreuses invitent à l'abus. Je limite donc non seulement les temps d'inactivité, mais aussi les délais d'attente de lecture et de corps. Sous Nginx, j'utilise client_header_timeout et client_body_timeout ; sous Apache, je définis des limites de lecture strictes à l'aide de modules appropriés afin qu'aucune requête lente ne bloque les workers. Les limites de taille d'en-tête et de corps de requête empêchent en outre le gonflement de la mémoire. Associées à des fenêtres Keep-Alive modérées, elles réduisent le risque que quelques clients occupent de nombreux sockets. L'ordre reste important : d'abord des délais d'expiration corrects, puis des limites ciblées, enfin des règles liées au débit ou à l'adresse IP. C'est la seule façon de garantir la rapidité des utilisateurs réels, tandis que les profils d'attaque restent sans effet.

Surveillance et tests de charge

Après chaque modification, je mesure l'effet à l'aide d'outils tels que ab, wrk ou k6 et je regarde le 95e centile de la Latence. Je réduis d'abord le délai d'attente par paliers clairs et observe si les délais d'attente ou les interruptions de connexion augmentent ; j'ajuste ensuite le nombre de requêtes par connexion. En parallèle, j'évalue les sockets ouverts, la charge de travail et les besoins en mémoire afin de réduire les temps morts au bon endroit. Pour les temps d'attente récurrents, il est utile de jeter un œil aux files d'attente dans le backend, mot-clé Mise en file d'attente du serveur et la répartition des demandes. Ceux qui travaillent avec des points de mesure identifient rapidement les goulots d'étranglement et gagnent un temps précieux. Dépannage.

Pratiques en matière de journaux et de métriques

Je veux voir si les connexions sont réellement réutilisées. Sous Nginx, j'étends le format du journal pour inclure les compteurs de connexion et les durées ; les valeurs m'indiquent si les clients envoient beaucoup de requêtes par connexion ou s'ils ferment après un ou deux accès. Je procède de la même manière avec Apache afin de visualiser le nombre de requêtes par connexion. Cela me permet d'identifier les modèles qui bénéficient davantage du délai d'expiration ou de la limite de requêtes.

# Nginx : exemple de format de journal étendu log_format main_ext '$remote_addr $request ' 'conn=$connection reqs=$connection_requests ' 'rt=$request_time uct=$upstream_connect_time';

access_log /var/log/nginx/access.log main_ext ;
# Apache : LogFormat avec connexion et durée LogFormat " %h %r conn:%{c}L reqs:%{REQUESTS_PER_CONN}n time:%D " keepalive CustomLog logs/access_log keepalive

Dans le cadre du monitoring, outre la médiane, je m'intéresse surtout aux latences P95/P99, aux connexions actives, à la répartition des requêtes/connexions et aux erreurs (augmentation des 408/499). Si celles-ci augmentent avec une fenêtre Keep-Alive plus petite, je réduis modérément ; si la charge reste stable et la latence meilleure, j'ai trouvé le juste milieu.

Déploiement et redémarrages progressifs

Les rechargements et les mises à niveau sont compatibles avec Keep-Alive si je les planifie correctement. Avec Nginx, je mise sur des rechargements fluides et laisse les connexions Worker se dérouler de manière contrôlée au lieu de les couper brutalement. De courts délais d'inactivité permettent de libérer plus rapidement les anciens Worker. Sous Apache, j'utilise un graceful-Redémarrez et surveillez en parallèle mod_status ou les pages d'état afin que les requêtes en attente ne soient pas interrompues. Avant les déploiements importants, je réduis temporairement la fenêtre Keep-Alive afin de vider le système plus rapidement, puis je la ramène à la valeur cible après avoir vérifié la stabilité. Important : documentez les modifications et comparez-les avec les profils de charge afin d'éviter que des ralentissements passent inaperçus. Régressions s'insinuer.

Erreurs fréquentes et mesures correctives

Des créneaux horaires trop longs maintiennent les utilisateurs inactifs Connexions ouvertes et reportent le problème vers des goulots d'étranglement au niveau des travailleurs, ce qui ralentit sensiblement les nouveaux visiteurs. Les requêtes illimitées par connexion semblent élégantes, mais au final, la connexion par socket augmente et les pics de charge deviennent incontrôlables. Des fenêtres extrêmement courtes, inférieures à une seconde, obligent les navigateurs à se reconstruire en permanence, ce qui augmente les parts de handshake et rend le frontend saccadé. Les chaînes de proxy manquent souvent de cohérence : un maillon utilise HTTP/1.0 ou définit Connection: close, ce qui empêche la réutilisation. Je procède donc dans l'ordre suivant : vérifier l'activation, ajuster les délais d'attente par petits paliers, adapter les requêtes par connexion et ne les augmenter que si les mesures montrent un réel Avantages montrer.

Liste de contrôle pour une mise en œuvre rapide

Je commence par activer Keep-Alive et noter l'heure actuelle. Valeurs, afin de pouvoir revenir en arrière à tout moment. Ensuite, je règle le délai d'expiration sur trois secondes, je recharge la configuration et je vérifie les connexions ouvertes, la charge et les cascades dans le frontend. Si de nombreuses visites courtes interviennent, je réduis le délai à deux secondes ; si les API Long Polls s'accumulent, j'augmente modérément le délai à cinq à dix secondes. Je règle ensuite MaxKeepAliveRequests sur 300-500 et observe si des slots restent libres ou si des clients permanents puissants occupent les connexions trop longtemps. Après chaque étape, je mesure à nouveau, documente les effets et conserve la meilleure configuration. Combinaison fixe.

Bilan succinct

Une configuration correcte de Keep-Alive permet d'économiser des handshakes, de réduire la latence et d'offrir plus de air par requête. Avec des fenêtres temporelles courtes, mais pas trop courtes, et un nombre modéré de requêtes par connexion, l'hôte fonctionne de manière nettement plus fluide. Je mise sur de petites modifications avec des points de mesure clairs, plutôt que de tourner aveuglément vers des valeurs maximales. En orientant de manière cohérente l'hébergement, le proxy inverse et le backend vers la réutilisation, on gagne en rapidité d'interaction sans mobiliser inutilement des ressources. Au final, c'est la mesure qui compte : seuls les indicateurs réels montrent si le réglage a produit les résultats escomptés. Effet apporte.

Derniers articles