web-dev-qa-db-fra.com

http keep-alive à l'ère moderne

Ainsi, selon l'auteur haproxy, qui connaît une chose ou deux sur http:

Keep-alive a été inventé pour réduire l'utilisation du processeur sur les serveurs lorsque les processeurs étaient 100 fois plus lents. Mais ce qui n'est pas dit, c'est que les connexions persistantes consomment beaucoup de mémoire tout en n'étant utilisables par personne, sauf par le client qui les a ouvertes. Aujourd'hui en 2009, les CPU sont très bon marché et la mémoire est encore limitée à quelques gigaoctets par l'architecture ou le prix. Si un site doit être maintenu en vie, il y a un vrai problème. Les sites très chargés désactivent souvent la conservation pour prendre en charge le nombre maximal de clients simultanés. Le véritable inconvénient de ne pas avoir de maintien en vie est une latence légèrement augmentée pour récupérer des objets. Les navigateurs doublent le nombre de connexions simultanées sur des sites non persistants pour compenser cela.

(depuis http://haproxy.1wt.eu/ )

Est-ce conforme à l'expérience des autres peuples? c'est-à-dire sans maintien en vie - le résultat est-il à peine perceptible maintenant? (il vaut probablement la peine de noter qu'avec les websockets, etc. - une connexion est maintenue "ouverte" quel que soit l'état de conservation de toute façon - pour les applications très réactives). L'effet est-il plus important pour les personnes distantes du serveur - ou s'il existe de nombreux artefacts à charger à partir du même hôte lors du chargement d'une page? (Je pense que des choses comme CSS, les images et JS proviennent de plus en plus de CDN compatibles avec le cache).

Pensées?

(Je ne sais pas si c'est une chose serverfault.com, mais je ne traverserai pas de message jusqu'à ce que quelqu'un me dise de le déplacer là-bas).

92
Michael Neale

Salut puisque je suis l'auteur de cette citation, je répondrai :-)

Il existe deux gros problèmes sur les grands sites: les connexions simultanées et la latence. Les connexions simultanées sont causées par des clients lents qui mettent du temps à télécharger le contenu et par des états de connexion inactifs. Ces états de connexion inactifs sont provoqués par la réutilisation des connexions pour récupérer plusieurs objets, appelés maintien en vie, qui est encore augmentée par la latence. Lorsque le client est très proche du serveur, il peut faire un usage intensif de la connexion et s'assurer qu'elle n'est presque jamais inactive. Cependant, lorsque la séquence se termine, personne ne se soucie de fermer rapidement le canal et la connexion reste ouverte et inutilisée pendant longtemps. C'est la raison pour laquelle de nombreuses personnes suggèrent d'utiliser un délai d'expiration très bas. Sur certains serveurs comme Apache, le délai d'expiration le plus bas que vous pouvez définir est d'une seconde, et c'est souvent beaucoup trop pour supporter des charges élevées: si vous avez 20000 clients devant vous et qu'ils récupèrent en moyenne un objet chaque seconde, vous aurez avoir ces 20000 connexions établies de façon permanente. 20000 connexions simultanées sur un serveur à usage général comme Apache sont énormes, nécessiteront entre 32 et 64 Go de RAM selon les modules chargés, et vous ne pouvez probablement pas espérer aller beaucoup plus haut même en ajout de RAM. En pratique, pour 20000 clients, vous pouvez même voir 40000 à 60000 connexions simultanées sur le serveur car les navigateurs essaieront de configurer 2 à 3 connexions s'ils ont de nombreux objets à récupérer.

Si vous fermez la connexion après chaque objet, le nombre de connexions simultanées diminuera considérablement. En effet, il diminuera d'un facteur correspondant au temps moyen de téléchargement d'un objet par le temps entre les objets. Si vous avez besoin de 50 ms pour télécharger un objet (une photo miniature, un bouton, etc ...), et que vous téléchargez en moyenne 1 objet par seconde comme ci-dessus, alors vous n'aurez que 0,05 connexion par client, ce qui n'est que 1000 connexions simultanées pour 20000 clients.

Maintenant, le temps d'établir de nouvelles connexions va compter. Les clients éloignés connaîtront une latence désagréable. Dans le passé, les navigateurs utilisaient de grandes quantités de connexions simultanées lorsque keep-alive était désactivé. Je me souviens de chiffres de 4 sur MSIE et de 8 sur Netscape. Cela aurait vraiment divisé le temps de latence moyen par objet. Maintenant que Keep-Alive est présent partout, nous ne voyons plus ce nombre élevé, car cela augmente encore la charge sur les serveurs distants et les navigateurs prennent soin de protéger l'infrastructure Internet.

Cela signifie qu'avec les navigateurs actuels, il est plus difficile d'obtenir des services non persistants aussi réactifs que les services persistants. De plus, certains navigateurs (par exemple: Opera) utilisent des heuristiques pour essayer d'utiliser le pipelinining. Le pipelining est un moyen efficace d'utiliser keep-alive, car il élimine presque la latence en envoyant plusieurs demandes sans attendre de réponse. Je l'ai essayé sur une page avec 100 petites photos, et le premier accès est environ deux fois plus rapide que sans maintien en vie, mais le prochain accès est environ 8 fois plus rapide, car les réponses sont si petites que seule la latence compte (seulement "304" réponses).

Je dirais que, idéalement, nous devrions avoir des paramètres ajustables dans les navigateurs pour leur permettre de maintenir les connexions entre les objets récupérés, et de les supprimer immédiatement lorsque la page est terminée. Mais nous ne voyons pas cela malheureusement.

Pour cette raison, certains sites qui doivent installer des serveurs à usage général tels qu'Apache sur la face avant et qui doivent prendre en charge de grandes quantités de clients doivent généralement désactiver la conservation. Et pour forcer les navigateurs à augmenter le nombre de connexions, ils utilisent plusieurs noms de domaine afin que les téléchargements puissent être parallélisés. C'est particulièrement problématique sur les sites utilisant intensivement SSL car la configuration de la connexion est encore plus élevée car il y a un aller-retour supplémentaire.

Ce qui est plus couramment observé de nos jours, c'est que ces sites préfèrent installer des frontaux légers tels que haproxy ou nginx, qui n'ont aucun problème à gérer des dizaines à des centaines de milliers de connexions simultanées, ils permettent de rester en vie côté client et de le désactiver sur Côté Apache. De ce côté, le coût d'établissement d'une connexion est presque nul en termes de CPU, et pas du tout perceptible en termes de temps. De cette façon, cela offre le meilleur des deux mondes: faible latence en raison de la persistance avec des délais d'attente très faibles du côté client et un faible nombre de connexions côté serveur. Tout le monde est content :-)

Certains produits commerciaux améliorent encore cela en réutilisant les connexions entre l'équilibreur de charge frontale et le serveur et en multiplexant toutes les connexions client sur eux. Lorsque les serveurs sont proches de la LB, le gain n'est pas beaucoup plus élevé que la solution précédente, mais cela nécessitera souvent des adaptations sur l'application pour éviter tout risque de croisement de session entre utilisateurs en raison du partage inattendu d'une connexion entre plusieurs utilisateurs . En théorie, cela ne devrait jamais se produire. La réalité est bien différente :-)

140
Willy Tarreau

Depuis que cela a été écrit (et affiché ici sur stackoverflow), nous avons maintenant des serveurs tels que nginx qui gagnent en popularité.

nginx, par exemple, peut maintenir ouvertes 10 000 connexions persistantes en un seul processus avec seulement 2,5 Mo (mégaoctets) de RAM. En fait, il est facile de maintenir plusieurs milliers de connexions ouvertes avec très peu de RAM, et les seules limites que vous atteindrez seront d'autres limites telles que le nombre de descripteurs de fichiers ouverts ou les connexions TCP TCP.

Keep-Alive était un problème non pas à cause d'un problème avec la spécification Keep-Alive elle-même mais à cause du modèle de mise à l'échelle basé sur les processus d'Apache et des Keep-Alives piratés sur un serveur dont l'architecture n'était pas conçue pour l'adapter.

Apache Prefork + mod_php + keep-alives est particulièrement problématique. C'est un modèle où chaque connexion continue à occuper tous les RAM qu'un processus PHP occupe, même s'il est complètement inactif et ne reste ouvert qu'en tant que keep-alive. Ce n'est pas évolutif. Mais les serveurs ne doivent pas être conçus de cette façon - il n'y a pas de raison particulière qu'un serveur doive conserver chaque connexion keep-alive dans un processus séparé (surtout pas quand chaque processus a un full = PHP). PHP-FPM et un modèle de traitement de serveur basé sur les événements comme celui de nginx résolvent le problème avec élégance.

Mise à jour 2015:

SPDY et HTTP/2 remplacent la fonctionnalité de maintien en vie de HTTP par quelque chose d'encore mieux: la capacité non seulement de maintenir en vie une connexion et de faire plusieurs demandes et réponses par-dessus, mais pour qu'elles soient multiplexées, afin que les réponses puissent être envoyées dans n'importe quel ordre , et en parallèle, plutôt que seulement dans l'ordre où elles ont été demandées. Cela empêche les réponses lentes de bloquer les réponses plus rapides et supprime la tentation pour les navigateurs de maintenir ouvertes plusieurs connexions parallèles à un seul serveur. Ces technologies mettent en évidence les insuffisances de l'approche mod_php et les avantages de quelque chose comme un serveur Web basé sur des événements (ou à tout le moins, multi-thread) couplé séparément avec quelque chose comme PHP-FPM.

22
thomasrutter

ma compréhension était que cela avait peu à voir avec le CPU, mais la latence dans l'ouverture de sockets répétées à l'autre bout du monde. même si vous avez une bande passante infinie, la latence de connexion ralentira tout le processus. amplifié si votre page contient des dizaines d'objets. même une connexion persistante a une latence de demande/réponse mais elle est réduite lorsque vous avez 2 sockets car en moyenne, l'une devrait diffuser des données tandis que l'autre pourrait être bloquante. De plus, un routeur ne supposera jamais qu'un socket se connecte avant de vous laisser y écrire. Il a besoin d'une poignée de main aller-retour complète. encore une fois, je ne prétends pas être un expert, mais c'est comme ça que je l'ai toujours vu. ce qui serait vraiment cool, c'est un protocole entièrement ASYNC (non, pas un protocole complètement malade).

2
catchpolenet

Des durées de conservation très longues peuvent être utiles si vous utilisez un CDN "Origin pull" tel que CloudFront ou CloudFlare. En fait, cela peut s'avérer plus rapide qu'aucun CDN, même si vous diffusez du contenu complètement dynamique.

Si vous gardez longtemps en vie de sorte que chaque PoP dispose d'une connexion permanente à votre serveur, la première fois que les utilisateurs visitent votre site, ils peuvent faire une poignée de main rapide TCP avec leur PoP local au lieu de une poignée de main lente avec vous. (La lumière elle-même prend environ 100 ms pour parcourir la moitié du monde via la fibre, et l'établissement d'une connexion TCP connexion nécessite trois paquets pour être transmis d'avant en arrière. SSL nécessite trois allers-retours .)

2
mjs