Pourquoi les connexions à l'état FIN_WAIT2 ne sont-elles pas fermées par le noyau Linux?

11

J'ai un problème dans un processus de longue durée appelé kube-proxy faisant partie de Kubernetes .

Le problème est que de temps en temps une connexion est laissée dans l'état FIN_WAIT2.

$ 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

Ces connexions s'empilent au fil du temps, ce qui rend le processus inapproprié. J'ai déjà signalé un problème à Kubernetes bug-tracker mais j'aimerais comprendre pourquoi de telles connexions ne sont pas fermées par le noyau Linux.

Selon sa documentation (recherche de tcp_fin_timeout), la connexion dans l'état FIN_WAIT2 devrait être fermée par le noyau après X secondes, où X peut être lu depuis / proc. Sur ma machine, il est réglé sur 60:

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

donc si je comprends bien, ces connexions doivent être fermées de 60 secondes. Mais ce n'est pas le cas, ils sont laissés dans cet état pendant des heures.

Bien que je comprenne également que les connexions FIN_WAIT2 sont assez inhabituelles (cela signifie que l'hôte attend un ACK de l'extrémité distante de la connexion qui pourrait déjà avoir disparu), je ne comprends pas pourquoi ces connexions ne sont pas "fermées" par le système .

Y a-t-il quelque chose que je puisse faire à ce sujet?

Notez que le redémarrage du processus associé est un dernier recours.

Adam Romanek
la source
1
Par ailleurs, dans FIN-WAIT2, la connexion n'attend pas un ACK (le FIN qu'il a envoyé a déjà été acquitté, c'est pourquoi nous ne sommes pas dans FIN-WAIT1). À la place, l'autre extrémité a toujours la possibilité d'envoyer une quantité illimitée de données.
Hagen von Eitzen

Réponses:

14

Le délai d'expiration du noyau s'applique uniquement si la connexion est orpheline. Si la connexion est toujours attachée à un socket, le programme propriétaire de ce socket est responsable de la temporisation de l'arrêt de la connexion. Il a probablement appelé shutdownet attend que la connexion s'arrête proprement. L'application peut attendre aussi longtemps qu'elle le souhaite pour que l'arrêt se termine.

Le flux d'arrêt propre typique se présente comme suit:

  1. L'application décide de fermer la connexion et ferme le côté écriture de la connexion.

  2. L'application attend que l'autre côté ferme sa moitié de connexion.

  3. L'application détecte l'arrêt de la connexion de l'autre côté et ferme son socket.

L'application peut attendre à l'étape 2 aussi longtemps qu'elle le souhaite.

Il semble que l'application ait besoin d'un délai d'attente. Une fois qu'il décide de fermer la connexion, il devrait renoncer à attendre que l'autre côté fasse un arrêt net après un certain temps.

David Schwartz
la source
Je vérifierai ces informations avec les développeurs de Kubernetes pour voir si un tel délai est implémenté. J'accepterai la réponse une fois que je la vérifierai. Merci néanmoins pour une réponse rapide.
Adam Romanek
J'aimerais comprendre votre réponse plus en détail. Pourriez-vous expliquer ce qu'est une connexion orpheline?
Adam Romanek
1
@AdamRomanek Une connexion orpheline est une connexion sans socket associée, c'est-à-dire accessible uniquement par le noyau lui-même et sur laquelle aucun processus ne peut effectuer d'opération.
David Schwartz
Cela aiderait ... " blog.cloudflare.com/…
John Greene
2

Si le socket est shutdown (), mais pas encore close (), le socket restera dans l'état FIN_WAIT2. Et puisque l'application possède toujours le descripteur de fichier, le noyau ne prendrait pas la peine de nettoyer.

L. Yan
la source
Cela est déjà mentionné dans la réponse acceptée.
RalfFriedl
J'ai spécifiquement ajouté que close () n'est pas appelé.
L. Yan