Wie funktioniert serverseitiges „TIME_WAIT“ wirklich?

Wie funktioniert serverseitiges „TIME_WAIT“ wirklich?

Ich weiß, dass es dazu ziemlich viele SE-Fragen gibt, und ich glaube, ich habe so viele davon gelesen, wie wichtig sind, bevor ich zu diesem Punkt gelangt bin.

Mit „serverseitig TIME_WAIT“ meine ich den Zustand eines serverseitigen Socket-Paares, dessen close() auf der Serverseite initiiert wurde.

Ich sehe oft diese für mich widersprüchlichen Aussagen:

  1. Serverseitig TIME_WAITist harmlos
  2. Sie sollten Ihre Netzwerk-Apps so gestalten, dass Clients close() initiieren, sodass der Client dieTIME_WAIT

Der Grund, warum ich das als widersprüchlich empfinde, liegt darin, dass TIME_WAITauf dem Client ein Problem auftreten kann. Dem Client können nicht genügend Ports zur Verfügung stehen. Daher wird oben im Wesentlichen empfohlen, die Belastung von TIME_WAITder Serverseite, wo es kein Problem gibt, auf die Clientseite zu verlagern, wo es problematisch sein kann.

Clientseitig TIME_WAITist natürlich nur in einer begrenzten Anzahl von Anwendungsfällen ein Problem. Die meisten Client-Server-Lösungen umfassen einen Server und viele Clients. Clients verarbeiten normalerweise nicht so viele Verbindungen, dass dies ein Problem darstellen würde, und selbst wenn dies der Fall ist, gibt es eine Reihe von Empfehlungen, um SO_LINGERclientseitig „vernünftig“ (im Gegensatz zu 0 Timeout oder dem Herumspielen mit tcp_tw-Sysctls) zu bekämpfen, TIME_WAITindem vermieden wird, zu viele Verbindungen zu schnell herzustellen. Dies ist jedoch nicht immer machbar, beispielsweise für Anwendungsklassen wie:

  • Überwachungssysteme
  • Lastgeneratoren
  • Proxys

Auf der anderen Seite verstehe ich nicht einmal, wie die Serverseite TIME_WAITüberhaupt hilfreich sein kann. Der Grund TIME_WAITdafür ist, dass sie das Einfügen veralteter TCPFragmente in Streams verhindert, zu denen sie nicht mehr gehören. Auf der Clientseite TIME_WAITwird dies erreicht, indem es einfach unmöglich gemacht wird, eine Verbindung mit denselben ip:portPaaren herzustellen, die diese veraltete Verbindung hätte haben können (die verwendeten Paare werden durch gesperrt TIME_WAIT). Auf der Serverseite kann dies jedoch nicht verhindert werden, da die lokale Adresse den akzeptierenden Port hat und immer derselbe sein wird, und der Server kann (soweit ich weiß, habe ich nur den empirischen Beweis) die Verbindung nicht einfach ablehnen, weil ein eingehender Peer dasselbe Adresspaar erstellen würde, das bereits in der Socket-Tabelle vorhanden ist.

Ich habe ein Programm geschrieben, das zeigt, dass serverseitige TIME-WAIT ignoriert werden. Da der Test außerdem auf 127.0.0.1 durchgeführt wurde, muss der Kernel ein spezielles Bit haben, das ihm sogar sagt, ob es sich um eine Server- oder eine Client-Seite handelt (da sonst das Tupel dasselbe wäre).

Quelle:http://pastebin.com/5PWjkjEf, getestet auf Fedora 22, Standard-Netzkonfiguration.

$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp    TIME-WAIT  0      0            127.0.0.1:44400         127.0.0.1:44401   
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address

Auf der Serverseite TIME_WAITkonnten Verbindungen über genau dasselbe Portpaar sofort und erfolgreich wiederhergestellt werden, auf der Clientseite schlugen sie TIME-WAITbeim zweiten Durchlauf connect()zu Recht fehl.

Zusammenfassend lässt sich sagen, dass die Frage zweierlei ist:

  • Tut die Serverseite TIME_WAITwirklich nichts und bleibt nur so, weil es RFCerforderlich ist?
  • Wird dem Client empfohlen, close() zu initiieren, weil der Server TIME_WAITnutzlos ist?

Antwort1

InTCPDer Begriff „Serverseite“ bezieht sich hier auf den Host, der den Socket im LISTEN-Status hat.

RFC1122ermöglicht dem Socket im TIME-WAIT-Zustand, unter bestimmten Bedingungen neue Verbindungen anzunehmen

        When a connection is closed actively, it MUST linger in
        TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime).
        However, it MAY accept a new SYN from the remote TCP to
        reopen the connection directly from TIME-WAIT state, if it:

Genauere Informationen zu den Konditionen finden Sie in derRFC1122. Ich würde erwarten, dass es auch ein passendes passives OPEN am Socket geben muss (Socket im LISTEN-Zustand).

Active OPEN (Client Side Connect Call) hat keine solche Ausnahme und muss einen Fehler ausgeben, wenn sich der Socket im TIME-WAIT-Zustand befindet, gemäßRFC793.

Meine Vermutung bezüglich der Empfehlung für den Client (in TCP-Begriffen der Host, der aktiv OPEN ausführt, d. h. eine Verbindung herstellt) ist ähnlich wie Ihre, dass im Normalfall die TIME-WAIT-Sockets auf mehrere Hosts verteilt werden, wo es reichlich Ressourcen für die Sockets gibt. Im Normalfall senden Clients kein SYN, das TIME-WAIT-Sockets auf dem Server wiederverwenden würde. Ich stimme zu, dass die Anwendung einer solchen Empfehlung immer noch vom Anwendungsfall abhängt.

Antwort2

Der Client verwendet eine neue TCP-ISN (anfängliche Sequenznummer) basierend auf einem Algorithmus (der etwa alle 4 Mikrosekunden um 1 erhöht wird). Die ISN ist grundsätzlich immer größer als die Sequenznummer, die im letzten gleichen TCP-Socket-FIN „IP:Port-Paar“ gesendet wurde. Der Server akzeptiert also immer die neue SYN, auch wenn das „IP:Port-Paar“ auf dem Server noch im Status TIME_WAIT aufgezeichnet ist.

   RFC 793 [RFC0793] suggests that the choice of the ISN of a connection
   is not arbitrary, but aims to reduce the chances of a stale segment
   from being accepted by a new incarnation of a previous connection.
   RFC 793 [RFC0793] suggests the use of a global 32-bit ISN generator
   that is incremented by 1 roughly every 4 microseconds.

Antwort3

Dasist wahrscheinlich das klarste Beispiel dafür, was TIME-WAIT tatsächlich macht und, noch wichtiger, warum es wichtig ist. Es erklärt auch, warum man einige der „Expertentipps“ auf Linux-Rechnern vermeiden sollte, um TIME-WAITs zu „verkürzen“.

Antwort4

Bei einem unzuverlässigen Protokoll können Sie nie sicher sein, dass Sie die letzte Nachricht von Ihrem Peer-Gerät erhalten haben. Daher ist es gefährlich anzunehmen, dass Ihr Peer ziemlich plötzlich aufgelegt hat. Ein großer Nachteil des TCP-Protokolls ist, dass nur etwa 65.000 Ports gleichzeitig geöffnet sein können. Dies lässt sich jedoch durch den Wechsel zu einer Serverfarm umgehen, die sich besser mit der Last skalieren lässt, als durch schnelles Recycling von Portnummern. Auf der Clientseite ist es höchst unwahrscheinlich, dass Ihnen die Ports ausgehen, wenn es sich um eine einfache Workstation handelt.

verwandte Informationen