Por que as conexões no estado FIN_WAIT2 não são fechadas pelo kernel do Linux?

11

Eu tenho um problema em um processo de longa duração chamado proxy-kube que faz parte do Kubernetes .

O problema é que, de tempos em tempos, uma conexão é deixada no 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

Essas conexões se acumulam com o tempo, fazendo com que o processo se comporte mal. Eu já relatei um problema ao rastreador de erros do Kubernetes, mas gostaria de entender por que essas conexões não são fechadas pelo kernel do Linux.

De acordo com a documentação (procure tcp_fin_timeout), a conexão no estado FIN_WAIT2 deve ser fechada pelo kernel após X segundos, onde X pode ser lido em / proc. Na minha máquina, está definido como 60:

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

então, se eu entendi direito, essas conexões devem ser fechadas em 60 segundos. Mas este não é o caso, eles são deixados nesse estado por horas.

Embora eu também entenda que as conexões FIN_WAIT2 são bastante incomuns (significa que o host está aguardando por um ACK a partir da extremidade remota da conexão que já pode ter desaparecido), não entendo por que essas conexões não são "fechadas" pelo sistema .

Existe algo que eu possa fazer sobre isso?

Observe que reiniciar o processo relacionado é um último recurso.

Adam Romanek
fonte
1
A propósito, no FIN-WAIT2, a conexão não está aguardando um ACK (o FIN enviado já foi reconhecido, e é por isso que não estamos no FIN-WAIT1). Em vez disso, a outra extremidade ainda tem a opção de enviar uma quantidade ilimitada de dados.
Hagen von Eitzen

Respostas:

14

O tempo limite do kernel se aplica somente se a conexão for órfã. Se a conexão ainda estiver conectada a um soquete, o programa que possui esse soquete é responsável pelo tempo limite do desligamento da conexão. Provavelmente ele ligou shutdowne está aguardando a conexão ser desligada corretamente. O aplicativo pode esperar o tempo que for necessário para o encerramento.

O fluxo típico de desligamento limpo é assim:

  1. O aplicativo decide desligar a conexão e encerra o lado de gravação da conexão.

  2. O aplicativo aguarda o outro lado desligar a metade da conexão.

  3. O aplicativo detecta o desligamento do outro lado da conexão e fecha seu soquete.

O aplicativo pode esperar na etapa 2 pelo tempo que desejar.

Parece que o aplicativo precisa de um tempo limite. Uma vez que decida desligar a conexão, deve deixar de esperar que o outro lado faça um desligamento limpo após um período de tempo razoável.

David Schwartz
fonte
Vou verificar essas informações com os desenvolvedores do Kubernetes para ver se esse tempo limite está implementado. Aceito a resposta assim que a verificar. No entanto, obrigado pela resposta rápida.
23615 Adam Romanek
Gostaria de entender sua resposta com mais detalhes. Você poderia explicar o que é uma conexão órfã?
Adam Romanek
1
@AdamRomanek Uma conexão órfã é aquela sem soquetes associados, ou seja, aquela que só pode ser acessada pelo próprio kernel e que nenhum processo pode executar uma operação.
David Schwartz
Isso ajudaria ... " blog.cloudflare.com/…
John Greene
2

Se o soquete estiver desligado (), mas ainda não fechado (), o soquete permanecerá no estado FIN_WAIT2. E como o aplicativo ainda possui o descritor de arquivo, o kernel não se incomodaria em limpar.

L. Yan
fonte
Isso já é mencionado na resposta aceita.
precisa saber é o seguinte
Eu adicionei especificamente que close () não é chamado.
5282 Yan Yan