Dlaczego serwer nie wysyła pakietu SYN / ACK w odpowiedzi na pakiet SYN

46

Ostatnio zdaliśmy sobie sprawę z problemu z połączeniem TCP, który ogranicza się głównie do użytkowników komputerów Mac i Linux, którzy przeglądają nasze witryny.

Z perspektywy użytkownika przedstawia się jako bardzo długi czas połączenia z naszymi stronami internetowymi (> 11 sekund).

Udało nam się wyśledzić techniczną sygnaturę tego problemu, ale nie możemy zrozumieć, dlaczego tak się dzieje ani jak go naprawić.

Zasadniczo dzieje się tak, że komputer klienta wysyła pakiet SYN w celu nawiązania połączenia TCP, a serwer sieciowy go odbiera, ale nie odpowiada pakietem SYN / ACK. Po tym, jak klient wysłał wiele pakietów SYN, serwer w końcu odpowiada pakietem SYN / ACK i wszystko jest w porządku dla pozostałej części połączenia.

I, oczywiście, przyczyna problemu: jest sporadyczna i nie zdarza się cały czas (chociaż zdarza się to między 10-30% czasu)

Używamy Fedory 12 Linux jako systemu operacyjnego i Nginx jako serwera WWW.

Zrzut ekranu z analizy wireshark

Zrzut ekranu z analizy wireshark

Aktualizacja:

Wyłączenie skalowania okna na kliencie zatrzymało problem. Teraz potrzebuję tylko rozwiązania po stronie serwera (nie możemy zmusić wszystkich klientów do robienia tego) :)

Ostatnia aktualizacja:

Rozwiązaniem było wyłączenie skalowania okna TCP i znaczników czasu TCP na naszych serwerach, które są publicznie dostępne.

klucz kodowy
źródło
1
Myślę, że będziemy musieli zobaczyć, jak to się dzieje.
Coredump
Czy masz jakieś acls lub reguły oparte na odwrotnym DNS? Być może trzeba spojrzeć na coś więcej niż tylko połączenie między klientem a serwerem. Być może upłynął limit czasu wyszukiwania DNS?
Zoredache
@coredump: oto zrzut ekranu z analizy wireshark, która pokazuje problem i.imgur.com/Bnzrm.png (nie mogłem wymyślić, jak wyeksportować tylko strumień ....)
klucz kodowy
@Zoredache: nie, nie mamy żadnych acls ani reguł opartych na odwrotnym DNS. To jest publiczny serwer WWW i pozwalamy wszystkim na dostęp
codemonkey
Przeczucie, ale czy robisz jakieś ograniczenia prędkości połączeń przychodzących na serwerze? Powiedz, z iptables?
Steven Poniedziałek,

Odpowiedzi:

15

Mieliśmy ten sam problem. Wyłączenie znaczników czasu TCP rozwiązało problem.

sysctl -w net.ipv4.tcp_timestamps=0

Aby wprowadzić tę zmianę na stałe, wprowadź dane w polu /etc/sysctl.conf.

Należy bardzo uważać przy wyłączaniu opcji Skalowania okna TCP. Ta opcja jest ważna dla zapewnienia maksymalnej wydajności przez Internet. Ktoś z połączeniem 10 Mb / s będzie miał transfer nieoptymalny, jeśli czas podróży w obie strony (w zasadzie taki sam jak ping) jest dłuższy niż 55 ms.

Naprawdę zauważyliśmy ten problem, gdy za tym samym NATem było wiele urządzeń. Podejrzewam, że serwer mógł być zdezorientowany widząc znaczniki czasu z urządzeń z Androidem i maszyn OSX w tym samym czasie, ponieważ umieszczają one zupełnie inne wartości w polach znaczników czasu.

Mccizzle
źródło
4
W przypadku, gdy ktoś inny skończy tutaj przez tę samą króliczą dziurę, którą właśnie zszedłem: Przed wyłączeniem znaczników czasu TCP lub skalowania okna, które mogą mieć poważne konsekwencje wydajnościowe dla łącza o dużym natężeniu ruchu, sprawdź, czy twoim problemem jest tcp_tw_recycle: stackoverflow .pl / pytania / 8893888 /…
neftes
12

W moim przypadku następujące polecenie naprawiło problem z brakującymi odpowiedziami SYN / ACK z serwera Linux:

sysctl -w net.ipv4.tcp_tw_recycle=0

Myślę, że jest to bardziej poprawne niż wyłączenie znaczników czasu TCP, ponieważ znaczniki czasu TCP są przydatne do wysokiej wydajności (PAWS, skalowanie okien itp.).

Dokumentacja tcp_tw_recyclewyraźnie stwierdza, że ​​nie jest zalecane włączenie tej opcji, ponieważ wiele routerów NAT zachowuje znaczniki czasu, a zatem PAWS uruchamia się, ponieważ znaczniki czasu z tego samego adresu IP nie są spójne.

   tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)
          Enable fast recycling of TIME_WAIT sockets.  Enabling this
          option is not recommended for devices communicating with the
          general Internet or using NAT (Network Address Translation).
          Since some NAT gateways pass through IP timestamp values, one
          IP can appear to have non-increasing timestamps.  See RFC 1323
          (PAWS), RFC 6191.
lav
źródło
1
dobre wyjaśnienie tutaj: vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux Po stronie serwera nie włączaj net.ipv4.tcp_tw_recycle, chyba że masz pewność, że nigdy nie będziesz mieć urządzeń NAT w miksie.
Gnought
1
W moim przypadku net.ipv4.tcp_tw_recyclejest to prawdziwy powód. Dzięki.
bluearrow,
tcp_tw_recycle został usunięty w ostatnich jądrach. Czy istnieje inne podobne rozwiązanie? @nephtes sugeruje, że wyłączenie znacznika czasu obniża wydajność.
MappaM
Ponieważ tcp_tw_recycle został usunięty, problem nie powinien się powtórzyć, ponieważ zdarzyło się to tylko z inną niż domyślną wartością tcp_tw_recycle.
lav
5

Zastanawiam się, ale dlaczego w przypadku pakietu SYN (ramka 539; ta, która została zaakceptowana) w polach „Informacje” brakuje pól WS i TSV?

WS to Skalowanie okna TCP, a TSV to Wartość znacznika czasu . Oba znajdują się w polu tcp.options, a Wireshark nadal powinien je pokazywać, jeśli są obecne. Może podczas 8. próby stos TCP / IP klienta odmawia wysłania innego pakietu SYN i to był powód, dla którego został nagle potwierdzony?

Czy możesz podać nam wartości wewnętrzne ramki 539? Czy SYN / ACK zawsze przychodzi dla pakietu SYN, który nie ma włączonej WS?

Hans Solo
źródło
@Ansis: oto zrzuty ekranu dla szczegółów ramki 539 (musiał to zrobić w dwóch częściach): i.imgur.com/D84GC.png i i.imgur.com/4riq3.png
klucz kodowy
@codemonkey: Twój 8. pakiet SYN wydaje się być inny niż pierwsze siedem pakietów SYN. Czy serwer odpowiada SYN / ACK na SYN klienta tylko wtedy, gdy pole tcp.options ma rozmiar 8 bajtów (Pierwsze siedem pakietów SYN prawdopodobnie ma opcje tcp.options o rozmiarze 20 bajtów)? Czy można wyłączyć skalowanie okna TCP po stronie klienta, aby zobaczyć, czy problem zniknie? Wygląda na problem ze stosem TCP / IP po stronie serwera lub źle skonfigurowaną zaporą ogniową gdzieś ...
Hans Solo
@Ansis: tak, patrzyłem na to, odkąd zwróciłeś na to uwagę, a wszystkie pozostałe pakiety SYN mają 24 bajty. Spróbuję wyłączyć skalowanie okien na kliencie i rano sprawdzę wyniki ponownie.
klucz kodowy
@Ansis: wyłączenie skalowania systemu Windows na kliencie zatrzymało problem. Dzięki! Jednak teraz muszę wymyślić, jak to naprawić po stronie serwera (ponieważ nie możemy sprawić, aby wszyscy nasi klienci wyłączali skalowanie systemu Windows) :) Na omawianym serwerze jest net.ipv4.tcp_windows_scaling = 1
klucz kodowy
@Codemonkey: Zgadzam się, że wyłączenie WS na wszystkich klientach nie jest rozwiązaniem, ale przynajmniej śledziliśmy problem z problemami z rozmiarami WS / pakietów. Aby dalej znaleźć przyczynę, powinniśmy sprawdzić, jak skonfigurowana jest Twoja zapora ogniowa. Czy możesz ustanowić połączenia TCP z WS do różnych portów TCP? Z różnych źródłowych adresów IP?
Hans Solo
4

Właśnie natrafiliśmy na dokładnie ten sam problem (naprawdę zajęło sporo czasu przypięcie go do serwera, który nie wysyła synchronizacji).

„Rozwiązaniem było wyłączenie skalowania okien tcp i znaczników czasu tcp na naszych serwerach, które są publicznie dostępne”.

Alex Li
źródło
2

Aby kontynuować to, co stwierdził Ansis, widziałem takie problemy, gdy zapora nie obsługuje skalowania Windows TCP. Co to jest zapora marki / modelu między tymi dwoma hostami?

joeqwerty
źródło
Firewall to pudełko Fedory 13 korzystające z iptables. net.ipv4.tcp_windows_scaling jest również ustawiony na 1 na tym komputerze
klucz kodowy
2

Brak SYN / ACK może być spowodowany zbyt niskimi limitami ochrony SYNFLOOD na zaporze ogniowej. Zależy to od liczby połączeń z użytkownikiem serwera. Korzystanie ze spdy zmniejszyłoby liczbę połączeń i mogłoby pomóc w sytuacji, w której wyłączenie net.ipv4.tcp_timestampsnie pomaga.

brablc
źródło
1

Jest to zachowanie nasłuchującego gniazda TCP, gdy jego zaległość jest pełna.

Ngnix pozwala ustawić argument backlog nasłuchiwać w konfiguracji: http://wiki.nginx.org/HttpCoreModule#listen

posłuchaj 80 zaległości = liczba

Spróbuj ustawić wartość num na coś większego niż domyślny, np. 1024.

Nie udzielam żadnej gwarancji, że pełna kolejka nasłuchu jest twoim problemem, ale to dobra pierwsza rzecz do sprawdzenia.

akramer
źródło
dzięki za wskazówkę. Spróbuję tego. Ustawiliśmy zaległości na poziomie systemu operacyjnego, ale nie jawnie w konfiguracji Nginx. Zaktualizuję z wynikiem.
codemonkey
to wcale nie zmieniło zachowania. Zgadnij, to nie problem? lub jedyny problem ...
codemonkey
1
parametr zaległości na poziomie aplikacji steruje rozmiarem kolejki dla zakończonych połączeń TCP, tzn. zakończono 3-kierunkowy uścisk dłoni, tj. odebrano
synchronizację
1

Właśnie odkryłem, że klienci Linux Linux zmieniają swój pakiet SYN po 3 próbach i usuwają opcję skalowania okna. Wydaje mi się, że programiści jądra stwierdzili, że jest to częsta przyczyna awarii połączenia w Internecie

Wyjaśnia, dlaczego tym klientom udaje się połączyć po 11 sekundach (mój krótki test TCP SYN występuje po 9 sekundach w moim krótkim teście z ustawieniami domyślnymi)

Jeroen van Bemmel
źródło
0

Miałem podobny problem, ale w moim przypadku błędnie obliczono sumę kontrolną TCP. Klient stał za veth i uruchomił ethtool -K veth0 rx off tx off załatwiło sprawę.

Baroudi Safwen
źródło