Niższa przepustowość TCP z serwera 1 Gb / s niż z serwera 100 Mb / s przy dużym RTT

9

Dysponujemy infrastrukturą w kilku głównych lokalizacjach na całym świecie - Singapurze, Londynie i Los Angeles. RTT pomiędzy dowolnymi dwoma lokalizacjami wynosi ponad> 150ms.

Niedawno zaktualizowaliśmy wszystkie serwery, aby korzystały z łączy 1 Gb / s (od 100 Mb / s). Przeprowadziliśmy kilka testów opartych na TCP między serwerami w różnych lokalizacjach i uzyskaliśmy zaskakujące wyniki. Te wyniki są całkowicie powtarzalne.

  1. Od Los Angeles (100 Mb / s) do Londynu (100 Mb / s): przepustowość ~ 96 Mb / s
  2. Z Los Angeles (100 Mb / s) do Londynu (1 Gb / s): przepustowość ~ 96 Mb / s
  3. Od Los Angeles (1 Gb / s) do Londynu (100 Mb / s): przepustowość 10-40 Mb / s (lotna)
  4. Od Los Angeles (1 Gb / s) do Londynu (1 Gb / s): przepustowość 10-40 Mb / s (lotna)
  5. Od Los Angeles (1 Gb / s) do Los Angeles (1 Gb / s): przepustowość> 900 Mb / s

Wygląda na to, że ilekroć nadawca działa z prędkością 1 Gb / s, nasza przepustowość znacznie spada z powodu długich łączy.

Wcześniejsze podejście do testowania jest niezwykle proste - po prostu używam cURL, aby pobrać plik binarny 1 GB z serwera docelowego (więc w powyższym przypadku klient cURL działa na serwerze w Londynie i pobiera z LA, więc LA jest nadawcą) . Oczywiście używa to jednego połączenia TCP.

Powtarzając te same testy przez UDP przy użyciu iperf, problem znika!

  1. Od Los Angeles (100 Mb / s) do Londynu (100 Mb / s): przepustowość ~ 96 Mb / s
  2. Z Los Angeles (100 Mb / s) do Londynu (1 Gb / s): przepustowość ~ 96 Mb / s
  3. Od Los Angeles (1 Gb / s) do Londynu (100 Mb / s): przepustowość ~ 96 Mb / s
  4. Od Los Angeles (1 Gb / s) do Londynu (1 Gb / s): przepustowość> 250 Mb / s

Wskazuje to wprost na problem z konfiguracją TCP lub NIC / portu w moich oczach.

Na obu serwerach działa CentOS 6.x, z sześciennym TCP. Oba mają maksymalnie 8 MB okien wysyłania i odbierania TCP oraz włączone znaczniki czasu TCP i selektywne potwierdzenia. Ta sama konfiguracja TCP jest używana we wszystkich przypadkach testowych. Pełna konfiguracja TCP znajduje się poniżej:

net.core.somaxconn = 128
net.core.xfrm_aevent_etime = 10
net.core.xfrm_aevent_rseqth = 2
net.core.xfrm_larval_drop = 1
net.core.xfrm_acq_expires = 30
net.core.wmem_max = 8388608
net.core.rmem_max = 8388608
net.core.wmem_default = 131072
net.core.rmem_default = 131072
net.core.dev_weight = 64
net.core.netdev_max_backlog = 1000
net.core.message_cost = 5
net.core.message_burst = 10
net.core.optmem_max = 20480
net.core.rps_sock_flow_entries = 0
net.core.netdev_budget = 300
net.core.warnings = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_retrans_collapse = 1
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_abort_on_overflow = 0
net.ipv4.tcp_stdurg = 0
net.ipv4.tcp_rfc1337 = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_fack = 1
net.ipv4.tcp_reordering = 3
net.ipv4.tcp_ecn = 2
net.ipv4.tcp_dsack = 1
net.ipv4.tcp_mem = 1528512      2038016 3057024
net.ipv4.tcp_wmem = 4096        131072  8388608
net.ipv4.tcp_rmem = 4096        131072  8388608
net.ipv4.tcp_app_win = 31
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_frto = 2
net.ipv4.tcp_frto_response = 0
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_no_metrics_save = 0
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_tso_win_divisor = 3
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_abc = 0
net.ipv4.tcp_mtu_probing = 0
net.ipv4.tcp_base_mss = 512
net.ipv4.tcp_workaround_signed_windows = 0
net.ipv4.tcp_dma_copybreak = 4096
net.ipv4.tcp_slow_start_after_idle = 1
net.ipv4.tcp_available_congestion_control = cubic reno
net.ipv4.tcp_allowed_congestion_control = cubic reno
net.ipv4.tcp_max_ssthresh = 0
net.ipv4.tcp_thin_linear_timeouts = 0
net.ipv4.tcp_thin_dupack = 0

W załączeniu jest kilka zdjęć grafów IO Wireshark niektórych przypadków testowych (przepraszam, nie mogę jeszcze publikować zdjęć bezpośrednio):

Przypadek testowy 1 (100 Mb / s -> 100 Mb / s) - niezły, płynny transfer. Brak strat w schwytaniu. - http://103.imagebam.com/download/dyNftIGh-1iCFbjfMFvBQw/25498/254976014/100m.png

Przypadek testowy 3 (1 Gb / s -> 100 Mb / s) - przesłanie głosu pocztą elektroniczną, osiągnięcie prędkości zajmuje dużo czasu - nigdy nie osiąga prędkości 100 Mb / s. Jeszcze żadnych strat / retransmisji podczas przechwytywania! - http://101.imagebam.com/download/KMYXHrLmN6l0Z4KbUYEZnA/25498/254976007/1g.png

Podsumowując, gdy używane jest długie łącze z połączeniem 1 Gb / s, uzyskujemy znacznie niższą przepustowość TCP niż w przypadku połączenia 100 Mb / s.

Byłbym bardzo wdzięczny za wskazówki od ekspertów TCP!

Dzięki!

AKTUALIZACJA (29.05.2013):

Rozwiązaliśmy problem z przypadkiem testowym nr 4 powyżej (nadawca 1 Gb / s, odbiornik 1 Gb / s, w dużym RTT). Możemy teraz osiągnąć ~ 970 Mb / s w ciągu kilku sekund od rozpoczęcia transferu. Wydaje się, że problem dotyczy przełącznika używanego przez dostawcę hostingu. Przejście do innego rozwiązało to.

Jednak przypadek testowy nr 3 w większości pozostaje problematyczny. Jeśli mamy odbiornik działający z prędkością 100 Mb / s, a nadawca z prędkością 1 Gb / s, to widzimy około 2-3 minut oczekiwania na osiągnięcie przez odbiornik 100 Mb / s (ale teraz osiąga pełną prędkość, inaczej niż wcześniej). Gdy tylko obniżymy nadawcę do 100 Mb / s lub zwiększymy odbiornik do 1 Gb / s, problem znika i możemy przyspieszyć do pełnej prędkości za sekundę lub dwie.

Głównym powodem jest to, że widzimy straty, oczywiście wkrótce po rozpoczęciu transferu. Nie oznacza to jednak, że rozumiem, jak działa powolny start; szybkość interfejsu nie powinna mieć na to żadnego wpływu, ponieważ powinna być regulowana przez potwierdzenia z odbiornika.

Proszę o sugestie z wdzięcznością! Gdybym mógł zaoferować nagrodę tutaj, zrobiłbym to!

Sam
źródło
1
Czy używasz odciążania TCP na karcie sieciowej po obu stronach? Czy twoje użycie odciążania TCP różni się od 100M do 1G NIC? Jeśli jest to używane w którymkolwiek z przypadków testowych, warto powtórzyć testy z wyłączonym, aby sprawdzić, czy silnik odciążania TCP w karcie sieciowej 100M może przeszkadzać w działaniu komunikacji 1G (ten komentarz jest celowo
machanie
Dobre pytanie! Odciążanie segmentacji TCP jest wyłączone na obu końcach. Ogólne odciążenie segmentacji jest włączone na obu końcach. Powtórzyłem to również przy włączonym OSP i nie zrobiło to żadnej zauważalnej różnicy.
Sam
Spróbuj wyłączyć ogólne odciążenie segmentacji, przynajmniej po stronie 100
mln
Dzięki za sugestię, ale bez radości - te same wyniki z włączonym lub wyłączonym Gso po obu stronach.
Sam
1 Gb / s przy 150 ms + daje bardzo duże opóźnienie przepustowości, ponad 18 Mb. Co się stanie, jeśli podbijesz bufory gniazd? tcp_*mem = 4096 1048576 33554432Nie masz włączonych ramek Jumbo na łączach 1 Gb / s, prawda? To może gdzieś powodować fragmentację.
suprjami

Odpowiedzi:

1

Głównym problemem jest duże opóźnienie WAN. Będzie jeszcze gorzej, jeśli zginie także losowy pakiet.

1, tcp_mem również musi ustawić duży, aby przydzielić więcej pamięci. Na przykład ustaw go jako net.ipv4.tcp_mem = 4643328 6191104 9286656

2, możesz przechwytywać pakiety przez wireshark / tcpdump przez około kilka minut, a następnie analizować, czy utracił losowy pakiet. Możesz również przesłać plik pakietów, jeśli chcesz.

3, możesz spróbować dostroić inne parametry tcp np. ustaw tcp_westwood = 1 i tcp_bic = 1

HarryREN
źródło
Dzięki, ale próbowaliśmy już wszystkich. Opóźnienie WAN nie jest problemem - możemy uzyskać 100 Mb / s niemal natychmiast, jeśli użyjemy portów 100 Mb / s, ale gdy tylko zmieni się na 1 Gb / s, toast.
Sam
1

Rozwiązany! Aby uzyskać szczegółowe informacje, patrz http://comments.gmane.org/gmane.linux.drivers.e1000.devel/11813

Krótko mówiąc, wygląda na to, że podłączony serwer 1 Gb / s wysyłałby gwałtowny ruch w fazie wykładniczej fazy wzrostu TCP, który zalałby bufory w niektórych urządzeniach pośrednich (kto wie co). Pozostawia to dwie opcje:

1) Skontaktuj się z każdym pośrednim operatorem sieci i poproś, aby skonfigurowali odpowiednie bufory, aby umożliwić moją pożądaną przepustowość i RTT. Całkiem mało prawdopodobne! 2) Ogranicz wybuchy.

Zdecydowałem się ograniczyć każdy przepływ TCP, aby działał co najwyżej 100 Mb / s. Liczba tutaj jest dość dowolna - wybrałem 100 Mb / s wyłącznie dlatego, że wiedziałem, że poprzednia ścieżka może obsłużyć 100 Mb / s i nie potrzebowałem już więcej dla pojedynczego przepływu .

Mam nadzieję, że to pomoże komuś w przyszłości.

Sam
źródło
0

Powtarzając te same testy przez UDP przy użyciu iperf, problem znika!

Od Los Angeles (1 Gb / s) do Londynu (1 Gb / s): przepustowość> 250 Mb / s

Problem nie zniknął, ostrożnie 75% twoich pakietów jest upuszczanych? Jeśli TCP cały czas przechodzi w wolne uruchamianie, średnia przepustowość może być raczej niska.

Przy okazji, czy macie wzorce dla Londynu do LA i Londynu do Londynu?

Jens Timmerman
źródło
Zapomniałem wspomnieć, że klient jest powolny ... Jeśli powtórzymy z dwoma szybkimi klientami, osiągniemy ~ 970 Mb / s dwukierunkowo.
Sam