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

11

У меня есть проблема в долгоживущем процессе, называемом 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 от удаленного конца соединения, которое может уже отсутствовать), я не понимаю, почему эти соединения не «закрываются» системой ,

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

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

Адам Романек
источник
1
Кстати, в FIN-WAIT2 соединение не ожидает ACK (отправленный FIN уже был подтвержден, поэтому мы не в FIN-WAIT1). Вместо этого на другом конце все еще есть возможность отправлять неограниченное количество данных.
Хаген фон Айцен

Ответы:

14

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

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

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

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

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

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

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

Дэвид Шварц
источник
Я проверю эту информацию с разработчиками Kubernetes, чтобы увидеть, реализован ли такой таймаут. Я приму ответ, как только я его проверю. Тем не менее, спасибо за быстрый ответ.
Адам Романек
Я хотел бы понять ваш ответ более подробно. Не могли бы вы объяснить, что такое сиротская связь?
Адам Романек
1
@AdamRomanek Потерянное соединение - это соединение без связанных сокетов, то есть такое, к которому может обращаться только само ядро, и над которым ни один процесс не может выполнить операцию.
Дэвид Шварц
Это помогло бы ... " blog.cloudflare.com/…
Джон Грин
2

Если сокетом является shutdown (), но еще не close (), сокет останется в состоянии FIN_WAIT2. И так как приложение все еще владеет дескриптором файла, ядро ​​не потрудится очистить его.

Л. Ян
источник
Это уже упоминалось в принятом ответе.
Ральф Фридл
Я специально добавил, что close () не вызывается.
Л. Ян