http Keep-Alive in der Moderne

92

Also laut dem Haproxy-Autor, der ein oder zwei Dinge über http weiß:

Keep-Alive wurde erfunden, um die CPU-Auslastung auf Servern zu reduzieren, wenn die CPUs 100-mal langsamer waren. Was jedoch nicht gesagt wird, ist, dass dauerhafte Verbindungen viel Speicher verbrauchen, während sie von niemandem außer dem Client verwendet werden können, der sie geöffnet hat. Heute im Jahr 2009 sind CPUs sehr billig und der Speicher ist aufgrund der Architektur oder des Preises immer noch auf einige Gigabyte begrenzt. Wenn eine Site am Leben bleiben muss, gibt es ein echtes Problem. Hoch geladene Sites deaktivieren häufig Keep-Alive, um die maximale Anzahl gleichzeitiger Clients zu unterstützen. Der eigentliche Nachteil, wenn Sie nicht am Leben bleiben, ist eine leicht erhöhte Latenz beim Abrufen von Objekten. Browser verdoppeln die Anzahl gleichzeitiger Verbindungen auf nicht Keepalive-Sites, um dies auszugleichen.

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

Stimmt dies mit der Erfahrung anderer überein? dh ohne am Leben zu bleiben - ist das Ergebnis jetzt kaum noch spürbar? (Es ist wahrscheinlich erwähnenswert, dass mit Websockets usw. - eine Verbindung unabhängig vom Keep-Alive-Status ohnehin "offen" gehalten wird - für sehr reaktionsschnelle Apps). Ist der Effekt für Personen, die vom Server entfernt sind, größer - oder wenn beim Laden einer Seite viele Artefakte vom selben Host geladen werden müssen? (Ich würde denken, dass Dinge wie CSS, Bilder und JS zunehmend von cachefreundlichen CDNs stammen).

Gedanken?

(Ich bin mir nicht sicher, ob dies eine Sache von serverfault.com ist, aber ich werde den Beitrag erst überqueren, wenn mir jemand sagt, dass ich ihn dorthin verschieben soll.)

Michael Neale
quelle
1
Es ist erwähnenswert, dass an anderer Stelle in der Dokumentation für Haproxy, die am Leben bleibt, andere günstigere Begriffe erwähnt werden. Ich würde gerne etwas über die Erfahrungen der Menschen hören, insbesondere über Massenhosting.
Michael Neale
"Holen Sie sich einen besser gestalteten Web- / Anwendungsserver"? :-) Neuere Designs (wie Jetty) mit fortgesetzter (ähnlicher) Verbindungsbehandlung verringern die Speicher- / Thread-Probleme im Wesentlichen. Außerdem klingt "wenige GB" wie ein Serverbegriff 2008/2009
3
Es klingt für mich wie ein Trottel. Die zusätzliche RTT, die mit dem Einrichten einer neuen Steckdose verbunden ist, ist eine harte physikalische Grenze, die häufig lang genug ist, um für einen Menschen erkennbar zu sein, und nicht innerhalb der bekannten Gesetze der Physik reduziert werden kann. Umgekehrt ist RAM billig und wird immer billiger, und es gibt keinen Grund für einen freien Sockel, mehr als ein paar kB davon zu verwenden.
Will Dean
2
Interessant ist jedoch, dass dies nicht nur eine Theorie ist - dies ist der Autor von Haproxy. Alles andere, was ich höre, sind Theorien und Annahmen.
Michael Neale

Antworten:

141

Hey, da ich der Autor dieses Zitats bin, werde ich antworten :-)

Auf großen Websites gibt es zwei große Probleme: gleichzeitige Verbindungen und Latenz. Die gleichzeitige Verbindung wird durch langsame Clients verursacht, deren Herunterladen einige Zeit in Anspruch nimmt, und durch inaktive Verbindungsstatus. Diese Leerlaufverbindungszustände werden durch die Wiederverwendung der Verbindung zum Abrufen mehrerer Objekte verursacht, die als Keep-Alive bezeichnet wird, was durch die Latenz weiter erhöht wird. Wenn sich der Client sehr nahe am Server befindet, kann er die Verbindung intensiv nutzen und sicherstellen, dass sie fast nie inaktiv ist. Wenn die Sequenz endet, kümmert sich niemand darum, den Kanal schnell zu schließen, und die Verbindung bleibt lange Zeit offen und unbenutzt. Dies ist der Grund, warum viele Leute vorschlagen, ein sehr geringes Keep-Alive-Timeout zu verwenden. Auf einigen Servern wie Apache beträgt das niedrigste Zeitlimit, das Sie festlegen können, eine Sekunde, und es ist oft viel zu viel, um hohe Lasten aufrechtzuerhalten: Wenn Sie 20000 Clients vor sich haben und diese durchschnittlich ein Objekt pro Sekunde abrufen, werden diese 20000 Verbindungen dauerhaft hergestellt. 20000 gleichzeitige Verbindungen auf einem Allzweckserver wie Apache sind riesig, erfordern je nach geladenen Modulen zwischen 32 und 64 GB RAM, und Sie können wahrscheinlich nicht hoffen, selbst durch Hinzufügen von RAM viel höher zu werden. In der Praxis werden bei 20000 Clients möglicherweise sogar 40000 bis 60000 gleichzeitige Verbindungen auf dem Server angezeigt, da Browser versuchen, 2 bis 3 Verbindungen einzurichten, wenn sie viele abzurufende Objekte haben. und Sie können wahrscheinlich nicht hoffen, viel höher zu gehen, selbst wenn Sie RAM hinzufügen. In der Praxis werden bei 20000 Clients möglicherweise sogar 40000 bis 60000 gleichzeitige Verbindungen auf dem Server angezeigt, da Browser versuchen, 2 bis 3 Verbindungen einzurichten, wenn sie viele abzurufende Objekte haben. und Sie können wahrscheinlich nicht hoffen, viel höher zu gehen, selbst wenn Sie RAM hinzufügen. In der Praxis werden bei 20000 Clients möglicherweise sogar 40000 bis 60000 gleichzeitige Verbindungen auf dem Server angezeigt, da Browser versuchen, 2 bis 3 Verbindungen einzurichten, wenn sie viele abzurufende Objekte haben.

Wenn Sie die Verbindung nach jedem Objekt schließen, sinkt die Anzahl der gleichzeitigen Verbindungen drastisch. In der Tat sinkt es um einen Faktor, der der durchschnittlichen Zeit zum Herunterladen eines Objekts bis zur Zeit zwischen Objekten entspricht. Wenn Sie zum Herunterladen eines Objekts (eines Miniaturfotos, einer Schaltfläche usw.) 50 ms benötigen und wie oben durchschnittlich 1 Objekt pro Sekunde herunterladen, haben Sie nur 0,05 Verbindungen pro Client, was nur 1000 entspricht gleichzeitige Verbindungen für 20000 Clients.

Jetzt zählt die Zeit, um neue Verbindungen herzustellen. Bei weit entfernten Clients tritt eine unangenehme Latenz auf. In der Vergangenheit verwendeten Browser große Mengen gleichzeitiger Verbindungen, wenn Keep-Alive deaktiviert war. Ich erinnere mich an Zahlen von 4 auf MSIE und 8 auf Netscape. Dies hätte die durchschnittliche Latenz pro Objekt wirklich durch so viel geteilt. Jetzt, da Keep-Alive überall vorhanden ist, sehen wir keine so hohen Zahlen mehr, da dies die Belastung der Remote-Server weiter erhöht und Browser den Schutz der Internetinfrastruktur gewährleisten.

Dies bedeutet, dass es mit heutigen Browsern schwieriger ist, die Nicht-Keep-Alive-Dienste so reaktionsschnell zu machen wie die Keep-Alive-Dienste. Einige Browser (z. B. Opera) verwenden Heuristiken, um Pipelinining zu verwenden. Pipelining ist eine effiziente Methode zur Verwendung von Keep-Alive, da es die Latenz nahezu eliminiert, indem mehrere Anforderungen gesendet werden, ohne auf eine Antwort zu warten. Ich habe es auf einer Seite mit 100 kleinen Fotos versucht, und der erste Zugriff ist ungefähr doppelt so schnell wie ohne Keep-Alive, aber der nächste Zugriff ist ungefähr achtmal so schnell, da die Antworten so klein sind, dass nur die Latenz zählt (nur) "304" Antworten).

Ich würde sagen, dass wir im Idealfall einige Tunables in den Browsern haben sollten, damit sie die Verbindungen zwischen abgerufenen Objekten am Leben erhalten und sie sofort löschen, wenn die Seite vollständig ist. Aber das sehen wir leider nicht.

Aus diesem Grund müssen einige Sites, die Allzweckserver wie Apache auf der Vorderseite installieren müssen und die eine große Anzahl von Clients unterstützen müssen, im Allgemeinen die Keep-Alive-Funktion deaktivieren. Um Browser zu zwingen, die Anzahl der Verbindungen zu erhöhen, verwenden sie mehrere Domainnamen, damit Downloads parallelisiert werden können. Dies ist besonders problematisch auf Websites, die SSL intensiv nutzen, da der Verbindungsaufbau noch höher ist, da es einen zusätzlichen Roundtrip gibt.

Was heutzutage häufiger beobachtet wird, ist, dass solche Sites Light-Frontends wie Haproxy oder Nginx bevorzugen, die problemlos Zehntausende von gleichzeitigen Verbindungen verarbeiten können. Sie ermöglichen es, auf der Clientseite am Leben zu bleiben und sie auf der Clientseite zu deaktivieren Apache Seite. Auf dieser Seite sind die Kosten für den Verbindungsaufbau in Bezug auf die CPU nahezu null und in Bezug auf die Zeit überhaupt nicht spürbar. Auf diese Weise bietet dies das Beste aus beiden Welten: geringe Latenz aufgrund von Keep-Alive mit sehr geringen Zeitüberschreitungen auf der Clientseite und geringe Anzahl von Verbindungen auf der Serverseite. Alle sind glücklich :-)

Einige kommerzielle Produkte verbessern dies weiter, indem sie Verbindungen zwischen dem Frontload-Balancer und dem Server wiederverwenden und alle Client-Verbindungen über diese multiplexen. Wenn sich die Server in der Nähe der LB befinden, ist der Gewinn nicht viel höher als bei der vorherigen Lösung, erfordert jedoch häufig Anpassungen an der Anwendung, um sicherzustellen, dass aufgrund der unerwarteten gemeinsamen Nutzung einer Verbindung zwischen mehreren Benutzern kein Risiko für Sitzungskreuzungen zwischen Benutzern besteht . Theoretisch sollte dies niemals passieren. Die Realität sieht anders aus :-)

Willy Tarreau
quelle
1
Vielen Dank für die vollständige und umfassende Antwort! Ich war etwas verwirrt von verschiedenen Kommentaren auf der Seite über Keep-Alive - aber das alles macht Sinn.
Michael Neale
Interessanterweise - Ich habe beobachtet, dass Chrome unter Linux eine am Leben gehaltene Verbindung über einige Sekunden hinweg wiederverwendet - dh es dauerte, bis ein anderer Tab geöffnet wurde - dieser andere Tab hatte einen anderen Hostnamen, wurde jedoch über einen DNS-Platzhalter auf denselben Server (Masse) aufgelöst virtuelles Hosting) - und damit die gleiche Verbindung wiederverwendet! (Dies hat mich überrascht, nicht die gute Sorte - offensichtlich ist es in Ordnung, wenn Keep Alive nur auf der Client-Seite ist).
Michael Neale
Ich hörte nur, "benutze etwas anderes als Apache und es ist keine große Sache". Was ich extrapoliert habe war "deaktiviere mod_php und Passagier und dann könnte sogar Apache eine Kampfchance haben".
coolaj86
@ CoolAJ86: Es geht absolut nicht darum, Apache zu verprügeln, und ich persönlich benutze es. Der Punkt ist, dass je allgemeiner der Server, desto weniger Optionen Sie skalieren müssen. Einige Module erfordern das Pre-Fork-Modell, dann können Sie nicht auf eine große Anzahl von Verbindungen skalieren. Aber wie erklärt ist es keine große Sache, da Sie es mit einer anderen freien Komponente wie Haproxy kombinieren können. Warum sollte jemand in diesem Fall alles ersetzen? Installieren Sie Haproxy besser, als Ihre Anwendung auf einem anderen Server erneut zu implementieren!
Willy Tarreau
22

In den Jahren, seit dies geschrieben wurde (und hier auf stackoverflow gepostet wurde), haben wir jetzt Server wie Nginx, die immer beliebter werden.

nginx kann beispielsweise 10.000 Keep-Alive-Verbindungen in einem einzigen Prozess mit nur 2,5 MB (Megabyte) RAM offen halten. Tatsächlich ist es einfach, mehrere Tausend Verbindungen mit sehr wenig RAM offen zu halten, und die einzigen Grenzen, die Sie treffen, sind andere Grenzen, wie die Anzahl der offenen Dateihandles oder TCP-Verbindungen.

Keep-Alive war ein Problem, nicht wegen eines Problems mit der Keep-Alive-Spezifikation selbst, sondern wegen des prozessbasierten Skalierungsmodells von Apache und wegen Keep-Alives, die in einen Server gehackt wurden, dessen Architektur nicht dafür ausgelegt war.

Besonders problematisch ist Apache Prefork + mod_php + keep-alives. Dies ist ein Modell, bei dem jede einzelne Verbindung weiterhin den gesamten RAM belegt, den ein PHP-Prozess belegt, auch wenn er vollständig inaktiv ist und nur als Keep-Alive geöffnet bleibt. Dies ist nicht skalierbar. Server müssen jedoch nicht auf diese Weise entworfen werden - es gibt keinen besonderen Grund, warum ein Server jede Keep-Alive-Verbindung in einem separaten Prozess halten muss (insbesondere nicht, wenn jeder dieser Prozesse über einen vollständigen PHP-Interpreter verfügt). PHP-FPM und ein ereignisbasiertes Serververarbeitungsmodell wie das in Nginx lösen das Problem elegant.

Update 2015:

SPDY und HTTP / 2 ersetzen die Keep-Alive-Funktionalität von HTTP durch etwas noch Besseres: Die Möglichkeit, eine Verbindung nicht nur am Leben zu erhalten und mehrere Anforderungen und Antworten darüber zu stellen, sondern sie auch zu multiplexen, sodass die Antworten in beliebiger Reihenfolge gesendet werden können und parallel und nicht nur in der Reihenfolge, in der sie angefordert wurden. Dies verhindert, dass langsame Antworten schnellere blockieren, und beseitigt die Versuchung für Browser, mehrere parallele Verbindungen zu einem einzelnen Server offen zu halten. Diese Technologien unterstreichen weiter die Unzulänglichkeiten des mod_php-Ansatzes und die Vorteile eines ereignisbasierten (oder zumindest multithreaded) Webservers, der separat mit etwas wie PHP-FPM gekoppelt ist.

thomasrutter
quelle
2

Mein Verständnis war, dass es wenig mit der CPU zu tun hatte, sondern mit der Latenz beim Öffnen wiederholter Sockets auf der anderen Seite der Welt. Selbst wenn Sie über eine unendliche Bandbreite verfügen, verlangsamt die Verbindungslatenz den gesamten Prozess. verstärkt, wenn Ihre Seite Dutzende von Objekten enthält. Selbst eine dauerhafte Verbindung hat eine Anforderungs- / Antwortlatenz, die sich jedoch verringert, wenn Sie durchschnittlich über zwei Sockets verfügen. Einer sollte Daten streamen, während der andere blockieren könnte. Außerdem wird ein Router niemals davon ausgehen, dass ein Socket eine Verbindung herstellt, bevor Sie darauf schreiben können. Es braucht den vollen Roundtrip-Handschlag. Auch hier behaupte ich nicht, ein Experte zu sein, aber so habe ich es immer gesehen. Was wirklich cool wäre, ist ein vollständig ASYNC-Protokoll (nein, kein vollständig krankes Protokoll).

catchpolenet
quelle
Ja - das wäre meine Annahme. Vielleicht ist es ein Kompromiss - es gibt einen Punkt, an dem die Latenz (aufgrund der Entfernung) bedeutet, dass es ein echtes Problem ist
Michael Neale
ok, moderne Typografie würde Sie dazu bringen, sich mit einem Proxy zu verbinden, der (vielleicht) in der Nähe ist. Aber erweitern Sie dann die Frage, ob Proxys dauerhafte Verbindungen verwenden sollen?
catchpolenet
@ Michael Neale auch, wegen Dingen wie TCP Slow-Start, ist die tatsächliche Latenzstrafe viel schlimmer als Sie erwarten würden.
MartinodF
Vielleicht ist der Kompromiss eine viel kürzere Zeitüberschreitung. Wenn Sie Anfragen gesichert haben, warum sollten Sie den Socket herunterfahren und erneut starten? Selbst 1 Sekunde würde es einer Seite ermöglichen, mit voller Persistenz zu laden und die Sockets sofort danach herunterzufahren.
catchpolenet
2

Sehr lange Keep-Alives können nützlich sein, wenn Sie ein "Origin Pull" -CDN wie CloudFront oder CloudFlare verwenden. Tatsächlich kann dies schneller als kein CDN sein, selbst wenn Sie vollständig dynamische Inhalte bereitstellen.

Wenn Sie lange am Leben bleiben, sodass jeder PoP grundsätzlich eine permanente Verbindung zu Ihrem Server hat, können Benutzer beim ersten Besuch Ihrer Site einen schnellen TCP-Handshake mit ihrem lokalen PoP durchführen, anstatt einen langsamen Handshake mit Ihnen. (Light selbst benötigt ungefähr 100 ms, um sich über Glasfaser um die halbe Welt zu bewegen. Für den Aufbau einer TCP-Verbindung müssen drei Pakete hin und her übertragen werden. SSL erfordert drei Roundtrips .)

mjs
quelle
1
Ich war versucht, +1 zu geben, aber dann hat Ihr zweiter Absatz diese falsche Bemerkung von Licht, das nur 10 ms braucht, um um die halbe Welt zu reisen. 10 ms Lichtgeschwindigkeit im Vakuum betragen 3000 km und 10 ms Lichtgeschwindigkeit in einer Faser sind nicht viel mehr als 2000 km; Auf halber Strecke um die Welt (entlang der Oberfläche) sind es 20.000 km. Das wären also 100 ms - wenn nur Ihre Faser direkt von London nach Sydney gehen würde, anstatt wahrscheinlich Afrika auf dem Seeweg zu umrunden oder den langen Weg durch Hawaii zu nehmen ...
Pyramiden
@pyramids Du hast recht, entweder habe ich das getippt oder nur vermasselt. Werde dich auf den neuesten Stand bringen.
mjs