¿Por qué el núcleo de Linux no cierra las conexiones en estado FIN_WAIT2?

11

Tengo un problema en un proceso de larga duración llamado kube-proxy que forma parte de Kubernetes .

El problema es que de vez en cuando se deja una conexión en estado 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

Estas conexiones se acumulan con el tiempo haciendo que el proceso se comporte mal. Ya informé un problema al rastreador de errores de Kubernetes, pero me gustaría entender por qué esas conexiones no están cerradas por el kernel de Linux.

De acuerdo con su documentación (buscar tcp_fin_timeout) la conexión en estado FIN_WAIT2 debe ser cerrada por el núcleo después de X segundos, donde X puede leerse desde / proc. En mi máquina está configurado en 60:

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

así que si lo entiendo correctamente, tales conexiones deberían cerrarse por 60 segundos. Pero este no es el caso, se dejan en ese estado durante horas.

Si bien también entiendo que las conexiones FIN_WAIT2 son bastante inusuales (significa que el host está esperando un ACK desde el extremo remoto de la conexión que podría haber desaparecido) No entiendo por qué estas conexiones no están "cerradas" por el sistema .

¿Hay algo que pueda hacer al respecto?

Tenga en cuenta que reiniciar el proceso relacionado es un último recurso.

Adam Romanek
fuente
1
Por cierto, en FIN-WAIT2, la conexión no está esperando un ACK (el FIN que ha enviado ya ha sido reconocido, por eso no estamos en FIN-WAIT1). En cambio, el otro extremo todavía tiene la opción de enviar una cantidad ilimitada de datos.
Hagen von Eitzen

Respuestas:

14

El tiempo de espera del núcleo solo se aplica si la conexión es huérfana. Si la conexión todavía está conectada a un zócalo, el programa que posee ese zócalo es responsable de agotar el tiempo de espera de la conexión. Probablemente ha llamado shutdowny está esperando que la conexión se cierre limpiamente. La aplicación puede esperar todo el tiempo que quiera para que se complete el apagado.

El flujo de apagado limpio típico es el siguiente:

  1. La aplicación decide cerrar la conexión y cierra el lado de escritura de la conexión.

  2. La aplicación espera a que el otro lado cierre su mitad de la conexión.

  3. La aplicación detecta el apagado de la conexión del otro lado y cierra su zócalo.

La aplicación puede esperar en el paso 2 todo el tiempo que quiera.

Parece que la aplicación necesita un tiempo de espera. Una vez que decide cerrar la conexión, debe dejar de esperar que la otra parte realice un apagado limpio después de un período de tiempo razonable.

David Schwartz
fuente
Comprobaré esta información con los desarrolladores de Kubernetes para ver si se implementa dicho tiempo de espera. Aceptaré la respuesta una vez que la verifique. Sin embargo, gracias por la rápida respuesta.
Adam Romanek
Me gustaría entender tu respuesta con mayor detalle. ¿Podría explicar qué es una conexión huérfana?
Adam Romanek
1
@AdamRomanek Una conexión huérfana es una sin sockets asociados, es decir, una conexión a la que solo puede acceder el núcleo y que ningún proceso puede realizar una operación.
David Schwartz
Esto ayudaría ... " blog.cloudflare.com/…
John Greene
2

Si el socket está apagado (), pero aún no está cerrado (), el socket permanecerá en el estado FIN_WAIT2. Y dado que la aplicación aún posee el descriptor de archivo, el núcleo no se molestaría en limpiar.

L. Yan
fuente
Eso ya se menciona en la respuesta aceptada.
RalfFriedl
Agregué específicamente que close () no se llama.
L. Yan