Назад | Перейти на главную страницу

Почему соединения в состоянии FIN_WAIT2 не закрываются ядром Linux?

У меня проблема в долгоживущем процессе под названием kube-proxy быть частью Kubernetes.

Проблема в том, что время от времени соединение остается в состоянии 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

Эти соединения со временем накапливаются, что приводит к неправильному функционированию процесса. я уже сообщил о проблеме в баг-трекер Kubernetes, но хотелось бы понять, почему такие соединения не закрываются ядром Linux.

Согласно его документация (поиск tcp_fin_timeout) соединение в состоянии FIN_WAIT2 должно быть закрыто ядром через X секунд, где X можно прочитать из / proc. На моей машине установлено значение 60:

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

так что, если я правильно понимаю, такие соединения должны быть закрыты на 60 секунд. Но это не так, их оставляют в таком состоянии часами.

Хотя я также понимаю, что соединения FIN_WAIT2 довольно необычны (это означает, что хост ожидает некоторого ACK от удаленного конца соединения, которое, возможно, уже пропало), я не понимаю, почему эти соединения не «закрываются» системой. .

Что я могу с этим поделать?

Обратите внимание, что перезапуск связанного процесса - последнее средство.

Тайм-аут ядра применяется только в том случае, если соединение потеряно. Если соединение все еще подключено к сокету, программа, владеющая этим сокетом, отвечает за тайм-аут отключения соединения. Вероятно, он позвонил shutdown и ожидает полного отключения соединения. Приложение может ждать завершения выключения сколь угодно долго.

Типичный алгоритм чистого отключения выглядит следующим образом:

  1. Приложение решает закрыть соединение и отключает сторону записи соединения.

  2. Приложение ожидает, пока другая сторона завершит свою половину соединения.

  3. Приложение обнаруживает отключение соединения другой стороной и закрывает свой сокет.

Приложение может ждать на шаге 2 сколько угодно долго.

Похоже, приложению требуется тайм-аут. После того, как он решит закрыть соединение, он должен перестать ждать, пока другая сторона выполнит полное отключение через некоторое разумное время.

Если сокет отключен (), но еще не закрыт (), сокет останется в состоянии FIN_WAIT2. А поскольку приложение по-прежнему владеет файловым дескриптором, ядро ​​не утруждает себя очисткой.