Jak naprawdę działa serwer „TIME_WAIT”?

11

Wiem, że istnieje wiele pytań na ten temat i uważam, że przeczytałem tyle z nich, ile ma to znaczenie, zanim dojdę do tego punktu.

Pod pojęciem „po stronie serwera TIME_WAIT” rozumiem stan pary gniazd po stronie serwera, której zainicjowano funkcję close () po stronie serwera.

Często widzę te stwierdzenia, które wydają mi się sprzeczne:

  1. Po stronie serwera TIME_WAITjest nieszkodliwy
  2. Powinieneś zaprojektować swoje aplikacje sieciowe tak, aby klienci inicjowali close (), dlatego też klient musi to zrobić TIME_WAIT

Powodem, dla którego uważam to za sprzeczne, jest to, że TIME_WAITna kliencie może być problem - klient może zabraknąć dostępnych portów, więc w zasadzie powyższe zaleca przeniesienie ciężaru TIME_WAITna stronę klienta, gdzie może być problem, z po stronie serwera, gdzie nie stanowi to problemu.

Po stronie klienta TIME_WAITjest oczywiście problem tylko w ograniczonej liczbie przypadków użycia. Większość rozwiązań klient-serwer obejmowałaby jeden serwer i wielu klientów, klienci zwykle nie radzą sobie z wystarczająco dużą liczbą połączeń, aby stanowiło to problem, a nawet jeśli tak, istnieje szereg zaleceń dotyczących „zdrowego” ( w przeciwieństwie do SO_LINGERlimitu czasu 0 lub wtrącania się w sysctls tcp_tw) walcz po stronie klienta TIME_WAIT, unikając zbyt szybkiego tworzenia zbyt wielu połączeń. Ale nie zawsze jest to wykonalne, na przykład w przypadku klas aplikacji takich jak:

  • systemy monitorowania
  • generatory obciążenia
  • pełnomocnicy

Z drugiej strony nawet nie rozumiem, w jaki sposób po stronie serwera TIME_WAITjest w ogóle pomocna. Powodem TIME_WAITjest nawet to, że zapobiega wstrzykiwaniu starych TCPfragmentów do strumieni, do których już nie należą. Po stronie klienta TIME_WAITosiąga się to po prostu przez uniemożliwienie utworzenia połączenia z tymi samymi ip:portparami, które mogło mieć to nieaktualne połączenie (używane pary są zablokowane TIME_WAIT). Ale po stronie serwera nie można temu zapobiec, ponieważ adres lokalny będzie miał port akceptujący i zawsze będzie taki sam, a serwer nie może (AFAIK, mam tylko dowód empiryczny) po prostu dlatego, że połączenie przychodzący peer utworzyłby tę samą parę adresów, która już istnieje w tabeli gniazd.

Napisałem program, który pokazuje, że TIME-WAIT po stronie serwera są ignorowane. Ponadto, ponieważ test został przeprowadzony na 127.0.0.1, jądro musi mieć specjalny bit, który mówi mu nawet, czy jest to po stronie serwera, czy po stronie klienta (ponieważ w przeciwnym razie krotka byłaby taka sama).

Źródło: http://pastebin.com/5PWjkjEf , przetestowane na Fedorze 22, domyślna konfiguracja sieci.

$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp    TIME-WAIT  0      0            127.0.0.1:44400         127.0.0.1:44401   
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address

Tak więc, po stronie serwera TIME_WAIT, połączenia na dokładnie tej samej parze portów mogą zostać natychmiast i pomyślnie ustanowione ponownie, a po stronie klienta TIME-WAIT, podczas drugiej iteracji connect()nie powiodło się

Podsumowując, pytanie jest dwojakie:

  • Czy po stronie serwera TIME_WAITtak naprawdę nic nie robi i tak zostało, ponieważ RFCwymaga tego?
  • Czy powodem jest to, że klient powinien zainicjować close (), ponieważ serwer TIME_WAITjest bezużyteczny?
Paweł Veselov
źródło
Nie zabraknie Ci portów, chyba że masz tylko 1 klienta. Masz 65535 portów dla każdej kombinacji adresu IP klient / serwer. Połączenie od 1.2.3.4:1111 różni się od 4.3.2.1:1111. Zajmuje tylko kilka bajtów pamięci dla każdego połączenia TIME_WAIT.
Marki555

Odpowiedzi:

1

W terminach TCP po stronie serwera oznacza tutaj host, który ma gniazdo w stanie LISTEN.

RFC1122 pozwala gniazdu w stanie TIME-WAIT zaakceptować nowe połączenie z pewnymi warunkami

        When a connection is closed actively, it MUST linger in
        TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime).
        However, it MAY accept a new SYN from the remote TCP to
        reopen the connection directly from TIME-WAIT state, if it:

Aby uzyskać szczegółowe informacje na temat warunków, zobacz RFC1122 . Spodziewałbym się, że na gnieździe musi również znajdować się pasywne OTWIERANIE pasywne (gniazdo w stanie LISTEN).

Aktywne OPEN (wywołanie połączenia po stronie klienta) nie ma takiego wyjątku i musi dawać błąd, gdy gniazdo jest w trybie CZAS OCZEKIWANIA, zgodnie z RFC793 .

Domyślam się, że zalecenie dla klienta (w kategoriach TCP host wykonujący aktywne OTWÓRZ tj. Połącz) zainicjowane zamknięcie jest bardzo podobne do twojego, ponieważ w powszechnym przypadku rozkłada gniazda TIME-WAIT na większej liczbie hostów, na których jest mnóstwo zasobów dla gniazda. W typowym przypadku klienci nie wysyłają SYN, który ponownie używałby gniazd TIME-WAIT na serwerze. Zgadzam się, że zastosowanie takiej rekomendacji nadal zależy od przypadku użycia.

Marko Kohtala
źródło
0

Jest to prawdopodobnie najbardziej wyraźny przykład tego, co faktycznie robi CZAS OCZEKIWANIA, a co ważniejsze, dlaczego jest taki ważny. Wyjaśnia również, dlaczego należy unikać niektórych „eksperckich” porad dotyczących maszyn z systemem Linux, aby „skrócić” CZAS OCZEKIWANIA.

Khushil
źródło
Nadal nie wyjaśnia, co się stanie, gdy połączenie klient-> serwer zostanie zainicjowane, a serwer zablokuje tę parę w CZASIE OCZEKIWANIA
Paweł Veselov
Zobacz stackoverflow.com/questions/1490196/… - Odpowiedź jest tym, czego szukasz.
Khushil
0

Sesja tcp jest identyfikowana przez krotkę (sourceIP, sourcePort, destIP, destPort). Dlatego TIME_WAIT działa na każdym połączeniu TCP.

Jeśli chodzi o stronę zamykającą, w niektórych scenariuszach zamknięcie po stronie klienta może zmniejszyć liczbę gniazd TIME_WAIT na serwerze, a tym samym nieznacznie zmniejszyć pamięć. W przypadkach, gdy przestrzeń gniazd może zostać wyczerpana (z powodu efemerycznego wyczerpania portu) (np. Chciwi klienci z wieloma połączeniami z tym samym serwerem), problem ten należy rozwiązać z dowolnej strony.

basos
źródło
Proszę wytłumacz; kiedy pytasz, czy TW po stronie serwera coś robi, zastanawiasz się, czy to samo połączenie może być ponownie użyte w okresie TW. Odpowiedź brzmi „nie”, ponieważ połączenie zdefiniowane przez krotkę zajmuje miejsce w tabeli tcp serwera. Jeśli klient wkrótce spróbuje otworzyć to samo połączenie, otrzyma RST, skutecznie odmawiając połączenia tcp. Nawiasem mówiąc, artykuł z Khushil jest bardzo opisowy.
basos
Bardzo przepraszam, twoja odpowiedź faktycznie odpowiada na pytanie, źle przeczytałem i wycofałem swój komentarz. Jednak wydaje się również niepoprawny, ponieważ mam kod, który wydaje się dowodzić, że nie ma ochrony po stronie serwera TIME_WAIT(zaktualizowałem pytanie o te informacje). @ Odniesienie Khushila nie obejmuje TIME_WAITwystarczająco szczegółowo przypadków po stronie serwera .
Paweł Veselov,
-2

Nigdy nie możesz mieć pewności co do niewiarygodnego protokołu, że otrzymałeś ostatnią wiadomość z urządzenia równorzędnego, dlatego niebezpieczne jest założenie, że twój rówieśnik odłożył słuchawkę dość nagle. Główną wadą protokołu TCP jest to, że tylko 65 000 portów może być otwartych jednocześnie. Ale sposobem na rozwiązanie tego problemu byłoby przejście do farmy serwerów, która lepiej skaluje się wraz z obciążeniem, niż poprzez szybkie odzyskiwanie numerów portów. Po stronie klienta jest bardzo mało prawdopodobne, że zabraknie portów, jeśli jest to podstawowa stacja robocza.

jrrk
źródło
Bardzo przepraszam, ale to nie odpowiada na moje pytanie.
Paweł Veselov,