Warum werden Verbindungen im Status FIN_WAIT2 vom Linux-Kernel nicht geschlossen?

11

Ich habe ein Problem in einem langlebigen Prozess namens kube-proxy , der Teil von Kubernetes ist .

Das Problem ist, dass von Zeit zu Zeit eine Verbindung im Status FIN_WAIT2 verbleibt.

$ sudo netstat -tpn | grep FIN_WAIT2
tcp6       0      0 10.244.0.1:33132        10.244.0.35:48936       FIN_WAIT2   14125/kube-proxy
tcp6       0      0 10.244.0.1:48340        10.244.0.35:56339       FIN_WAIT2   14125/kube-proxy
tcp6       0      0 10.244.0.1:52619        10.244.0.35:57859       FIN_WAIT2   14125/kube-proxy
tcp6       0      0 10.244.0.1:33132        10.244.0.50:36466       FIN_WAIT2   14125/kube-proxy

Diese Verbindungen stapeln sich im Laufe der Zeit, wodurch sich der Prozess schlecht verhält. Ich habe Kubernetes Bug-Tracker bereits ein Problem gemeldet , möchte aber verstehen, warum solche Verbindungen vom Linux-Kernel nicht geschlossen werden.

Gemäß seiner Dokumentation (Suche nach tcp_fin_timeout) sollte die Verbindung im Status FIN_WAIT2 nach X Sekunden vom Kernel geschlossen werden, wobei X aus / proc gelesen werden kann. Auf meinem Computer ist es auf 60 eingestellt:

$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60

Wenn ich es richtig verstehe, sollten solche Verbindungen um 60 Sekunden geschlossen sein. Dies ist jedoch nicht der Fall, sie bleiben stundenlang in einem solchen Zustand.

Obwohl ich auch verstehe, dass FIN_WAIT2-Verbindungen ziemlich ungewöhnlich sind (dies bedeutet, dass der Host auf eine Bestätigung vom Remote-Ende der Verbindung wartet, die möglicherweise bereits unterbrochen ist), verstehe ich nicht, warum diese Verbindungen vom System nicht "geschlossen" werden .

Kann ich etwas dagegen tun?

Beachten Sie, dass der Neustart des zugehörigen Prozesses ein letzter Ausweg ist.

Adam Romanek
quelle
1
Übrigens wartet in FIN-WAIT2 die Verbindung nicht auf eine Bestätigung (die von ihr gesendete FIN wurde bereits bestätigt, weshalb wir uns nicht in FIN-WAIT1 befinden). Stattdessen hat das andere Ende weiterhin die Möglichkeit, eine unbegrenzte Datenmenge zu senden.
Hagen von Eitzen

Antworten:

14

Das Kernel-Timeout gilt nur, wenn die Verbindung verwaist ist. Wenn die Verbindung weiterhin an einen Socket angeschlossen ist, ist das Programm, dem dieser Socket gehört, dafür verantwortlich, das Herunterfahren der Verbindung zu beenden. Wahrscheinlich hat es angerufen shutdownund wartet darauf, dass die Verbindung sauber heruntergefahren wird. Die Anwendung kann so lange warten, bis das Herunterfahren abgeschlossen ist.

Der typische saubere Abschaltfluss sieht folgendermaßen aus:

  1. Die Anwendung beschließt, die Verbindung zu beenden und die Schreibseite der Verbindung zu beenden.

  2. Die Anwendung wartet darauf, dass die andere Seite die Hälfte der Verbindung beendet.

  3. Die Anwendung erkennt das Herunterfahren der Verbindung durch die andere Seite und schließt den Socket.

Die Anwendung kann in Schritt 2 so lange warten, wie sie möchte.

Es hört sich so an, als ob die Anwendung eine Zeitüberschreitung benötigt. Sobald es sich entscheidet, die Verbindung zu beenden, sollte es aufhören, darauf zu warten, dass die andere Seite nach einer angemessenen Zeitspanne ein sauberes Herunterfahren durchführt.

David Schwartz
quelle
Ich werde diese Informationen mit Kubernetes-Entwicklern überprüfen, um festzustellen, ob ein solches Timeout implementiert ist. Ich werde die Antwort akzeptieren, sobald ich sie überprüft habe. Trotzdem danke für die schnelle Antwort.
Adam Romanek
Ich möchte Ihre Antwort genauer verstehen. Könnten Sie bitte erklären, was eine verwaiste Verbindung ist?
Adam Romanek
1
@AdamRomanek Eine verwaiste Verbindung ist eine Verbindung ohne zugeordnete Sockets, dh eine, auf die nur der Kernel selbst zugreifen kann und für die kein Prozess eine Operation ausführen kann.
David Schwartz
Dies würde helfen ... " blog.cloudflare.com/…
John Greene
2

Wenn der Socket heruntergefahren (), aber noch nicht geschlossen () ist, bleibt der Socket im Status FIN_WAIT2. Und da die Anwendung immer noch den Dateideskriptor besitzt, würde sich der Kernel nicht darum kümmern, aufzuräumen.

L. Yan
quelle
Das ist bereits in der akzeptierten Antwort erwähnt.
RalfFriedl
Ich habe ausdrücklich hinzugefügt, dass close () nicht aufgerufen wird.
L. Yan