Mam problem w długotrwałym procesie zwanym kube-proxy będącym częścią Kubernetes .
Problem polega na tym, że od czasu do czasu połączenie pozostaje w stanie 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
Połączenia te nakładają się z czasem, co powoduje, że proces jest nieprawidłowy. Zgłosiłem już problem do modułu śledzenia błędów Kubernetes, ale chciałbym zrozumieć, dlaczego takie połączenia nie są zamykane przez jądro Linuksa.
Zgodnie z jego dokumentacją (poszukiwanie tcp_fin_timeout) połączenie w stanie FIN_WAIT2 powinno zostać zamknięte przez jądro po X sekundach, z których X można odczytać z / proc. Na moim komputerze jest ustawiony na 60:
$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60
więc jeśli dobrze to rozumiem, takie połączenia powinny zostać zamknięte o 60 sekund. Ale tak nie jest, pozostają w takim stanie przez wiele godzin.
Chociaż rozumiem również, że połączenia FIN_WAIT2 są dość nietypowe (oznacza to, że host czeka na potwierdzenie ACK ze zdalnego końca połączenia, które może już zniknąć), nie rozumiem, dlaczego połączenia te nie są „zamykane” przez system .
Czy mogę coś z tym zrobić?
Pamiętaj, że ponowne uruchomienie powiązanego procesu jest ostatecznością.
źródło
Odpowiedzi:
Limit czasu jądra ma zastosowanie tylko wtedy, gdy połączenie jest osierocone. Jeśli połączenie jest nadal podłączone do gniazda, program, który jest właścicielem tego gniazda, jest odpowiedzialny za przekroczenie limitu czasu zamknięcia połączenia. Prawdopodobnie zadzwonił
shutdown
i czeka na czyste zamknięcie połączenia. Aplikacja może czekać tak długo, jak chce na zakończenie zamykania.Typowy przebieg czystego zamykania wygląda następująco:
Aplikacja decyduje się zamknąć połączenie i zamyka stronę zapisu połączenia.
Aplikacja czeka, aż druga strona zamknie połowę połączenia.
Aplikacja wykrywa zamknięcie połączenia przez drugą stronę i zamyka gniazdo.
Aplikacja może czekać na kroku 2 tak długo, jak chce.
Wygląda na to, że aplikacja potrzebuje limitu czasu. Gdy zdecyduje się zamknąć połączenie, powinien zrezygnować z czekania, aż druga strona wykona czyste zamknięcie po pewnym rozsądnym czasie.
źródło
Jeśli gniazdo jest jeszcze shutdown (), ale jeszcze nie close (), gniazdo pozostanie w stanie FIN_WAIT2. A ponieważ aplikacja nadal posiada deskryptor pliku, jądro nie zawracałoby sobie głowy czyszczeniem.
źródło