Чому з'єднання у стані FIN_WAIT2 не закриті ядром Linux?


11

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

Якщо сокет відключений (), але ще не закритий (), сокет залишиться у стані FIN_WAIT2. А оскільки програма все ще володіє дескриптором файлів, ядро ​​не покладається на очищення.


Про це вже сказано у прийнятій відповіді.
РальфФрідл

Я спеціально додав, що close () не називається.
Л. Ян
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.