Strojenie parametrów routingu IP systemu Linux - secret_interval i tcp_mem

30

Mieliśmy dzisiaj mały problem z przełączaniem awaryjnym z jedną z naszych maszyn wirtualnych HAProxy. Kiedy wkopaliśmy się w to, znaleźliśmy to:

26 stycznia 07:41:45 jądro haproxy2: [226818.070059] __ratelimit: 10 połączeń zwrotnych pomijanych
26 stycznia 07:41:45 jądro haproxy2: [226818.070064] Brak pamięci gniazda
26 stycznia 07:41:47 jądro haproxy2: [226819.560048] Brak pamięci gniazda
26 stycznia 07:41:49 jądro haproxy2: [226822.030044] Brak pamięci gniazda

Co, według tego linku , najwyraźniej ma to związek z niskimi ustawieniami domyślnymi dla net.ipv4.tcp_mem. Więc zwiększyliśmy je o 4x od wartości domyślnych (jest to Ubuntu Server, nie jestem pewien, czy smak Linuksa ma znaczenie):

obecne wartości to: 45984 61312 91968
nowe wartości to: 183936 245248 367872

Następnie zaczęliśmy widzieć dziwny komunikat o błędzie:

26 stycznia 08:18:49 jądro haproxy1: [2291.579726] Łańcuch skrótu trasy jest za długi!
26 stycznia 08:18:49 jądro haproxy1: [2291.579732] Dostosuj swój tajny_interwał!

Ciii… to tajemnica !!

Najwyraźniej ma to związek z /proc/sys/net/ipv4/route/secret_intervaldomyślną wartością 600 i kontroluje okresowe opróżnianie pamięci podręcznej trasy

secret_intervalInstruuje jądro, jak często się zdmuchnąć wszystkie wpisy hash trasa niezależnie od tego jak nowe / stare są. W naszym środowisku jest to ogólnie złe. Procesor będzie zajęty odbudowaniem tysięcy wpisów na sekundę za każdym razem, gdy pamięć podręczna zostanie wyczyszczona. Jednak uruchamiamy to raz dziennie, aby nie dopuścić do wycieków pamięci (choć nigdy nie mieliśmy).

Chociaż z przyjemnością to zmniejszamy, wydaje się dziwne zalecanie upuszczania całej pamięci podręcznej trasy w regularnych odstępach czasu , zamiast po prostu szybszego wypychania starych wartości z pamięci podręcznej trasy.

Po pewnym dochodzeniu znaleźliśmy, /proc/sys/net/ipv4/route/gc_elasticityktóra wydaje się lepszą opcją dla utrzymania rozmiaru tablicy tras:

gc_elasticitynajlepiej można opisać jako średnią głębokość wiadra, którą jądro zaakceptuje, zanim zacznie wygasać wpisy skrótu trasy. Pomoże to utrzymać górną granicę aktywnych tras.

Dostosowaliśmy elastyczność z 8 do 4, w nadziei, że pamięć podręczna trasy przycinała się bardziej agresywnie. secret_intervalNie czuje poprawne do nas. Ale istnieje wiele ustawień i nie jest jasne, które są naprawdę właściwą drogą, aby przejść tutaj.

  • / proc / sys / net / ipv4 / route / gc_elasticity (8)
  • / proc / sys / net / ipv4 / route / gc_interval (60)
  • / proc / sys / net / ipv4 / route / gc_min_interval (0)
  • / proc / sys / net / ipv4 / route / gc_timeout (300)
  • / proc / sys / net / ipv4 / route / secret_interval (600)
  • / proc / sys / net / ipv4 / route / gc_thresh (?)
  • rhash_entries (parametr jądra, domyślnie nieznany?)

Nie chcemy pogarszać routingu Linuksa , więc obawiamy się, że zepsujemy niektóre z tych ustawień.

Czy ktoś może doradzić, które parametry routingu najlepiej dostosować do wystąpienia HAProxy o dużym natężeniu ruchu?

Jeff Atwood
źródło

Odpowiedzi:

28

Nigdy nie spotkałem się z tym problemem. Prawdopodobnie powinieneś jednak zwiększyć szerokość tabeli skrótów, aby zmniejszyć jej głębokość. Za pomocą „dmesg” zobaczysz, ile aktualnie masz wpisów:

$ dmesg | grep '^IP route'
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)

Możesz zmienić tę wartość za pomocą parametru wiersza polecenia rozruchu jądra rhash_entries. Najpierw spróbuj ręcznie, a następnie dodaj go do swojego lilo.conflub grub.conf.

Na przykład: kernel vmlinux rhash_entries=131072

Możliwe, że masz bardzo ograniczoną tabelę skrótów, ponieważ przypisałeś niewiele pamięci do maszyny wirtualnej HAProxy (rozmiar skrótu trasy jest dostosowywany w zależności od całkowitej pamięci RAM).

W związku z tym tcp_membądź ostrożny. Twoje początkowe ustawienia sprawiają, że myślę, że działasz z 1 GB pamięci RAM, z czego 1/3 może być przydzielona do gniazd TCP. Teraz przydzieliłeś 367872 * 4096 bajtów = 1,5 GB pamięci RAM do gniazd TCP. Należy bardzo uważać, aby nie zabraknąć pamięci. Zasadniczą zasadą jest przydzielenie 1/3 pamięci HAProxy i kolejnej 1/3 stosowi TCP, a 1/3 pozostałej części systemu.

Podejrzewam, że twoja wiadomość „z pamięci gniazda” pochodzi z domyślnych ustawień w tcp_rmemi tcp_wmem. Domyślnie masz 64 kB przydzielone na wyjściu dla każdego gniazda i 87 kB na wejściu. Oznacza to w sumie 300 kB dla połączenia proxy, tylko dla buforów gniazd. Dodaj do tego 16 lub 32 kB dla HAProxy, a zobaczysz, że 1 GB pamięci RAM obsługuje tylko 3000 połączeń.

Zmieniając domyślne ustawienia tcp_rmemi tcp_wmem(parametr środkowy), możesz znacznie obniżyć pamięć. Otrzymuję dobre wyniki przy wartościach tak niskich jak 4096 dla bufora zapisu i 7300 lub 16060 w tcp_rmem(5 lub 11 segmentów TCP). Możesz zmienić te ustawienia bez ponownego uruchamiania, będą one jednak obowiązywać tylko dla nowych połączeń.

Jeśli wolisz, aby nie dotykać sysctls zbyt dużo, najnowsza HAProxy, 1,4-dev8, pozwala dostosować te parametry z konfiguracji globalnej, a po każdej stronie (klient lub serwer).

Mam nadzieję, że to pomoże!

Willy Tarreau
źródło
8

Out of socket memory errorJest często mylące. Przez większość czasu na serwerach podłączonych do Internetu nie oznacza to żadnego problemu związanego z brakiem pamięci. Jak wyjaśniłem bardziej szczegółowo w poście na blogu , najczęstszą przyczyną jest liczba gniazd sierocych. Gniazdo osierocone to gniazdo, które nie jest powiązane z deskryptorem pliku. W niektórych okolicznościach jądro wyda, Out of socket memory errornawet jeśli jesteś 2x lub 4x od limitu ( /proc/sys/net/ipv4/tcp_max_orphans). Zdarza się to często w usługach internetowych i jest to całkowicie normalne. Właściwy sposób postępowania w tym przypadku polega na dostrojeniu tcp_max_orphansco najmniej czterokrotnie większej liczby sierot, które normalnie widzisz przy największym natężeniu ruchu.

Nie słuchaj wszelkich porad, które zaleca strojenie tcp_memlub tcp_rmemlub tcp_wmemchyba że naprawdę wiesz co robisz. Osoby udzielające tych rad zazwyczaj tego nie robią. Ich voodoo jest często niewłaściwe lub nieodpowiednie dla twojego środowiska i nie rozwiąże twojego problemu. Może to nawet pogorszyć.

tsuna
źródło
1
Kiedy tak się dzieje, komunikat jest inny w dmesg, widzisz „zbyt wiele osieroconych gniazd”. Zgadzam się jednak z tobą, że sieroty mogą pochłaniać ogromną ilość pamięci.
Willy Tarreau,
Po przekroczeniu liczby /proc/sys/net/ipv4/tcp_max_orphanswystąpi inny błąd. Na przykład cały stos stosu wymiany ma /proc/sys/net/ipv4/tcp_max_orphans65536 i /proc/net/sockstatpowoduje TCP: inuse 2996 sierota 171 tw 15972 przydzieli 2998 mem 1621 - różnicy, której nie można zignorować.
Geoff Dalgas
-4

Regularnie dostosowujemy niektóre z tych parametrów. Nasz standard dla platform transakcyjnych o wysokiej przepustowości i niskim opóźnieniu to:

net.ipv4.tcp_rmem = 4096 16777216 33554432
net.ipv4.tcp_wmem = 4096 16777216 33554432
net.ipv4.tcp_mem = 4096 16777216 33554432
net.core.rmem_default = 16777216
net.core.wmem_default = 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 30000
net.core.netdev_max_backlog = 30000
Scott Alan Miller
źródło
1
według matematyki Willy'ego, co oznacza, że ​​twoje standardowe ciśnienie w pamięci # (środkowa liczba) wynosi 68 GB ?! Razy trzy (rmem, wmem, mem) ??
Jeff Atwood
10
Te przestrajalne są błędne i bardzo często można je znaleźć w środowiskach laboratoryjnych, a następnie na ślepo wkleić. Nie będą mieć problemu z kilkoma równoległymi sesjami, ale nawet przy 100 gniazdach TCP przydzielisz 3,2 GB pamięci RAM. Dopóki opóźnienie jest niskie, nie zauważysz niczego podejrzanego. Musisz tylko odłączyć zdalną maszynę podczas przesyłania, aby zobaczyć, czy bufory wyjściowe się zapełniają, lub zamrozić lokalne zadanie i zobaczyć, jak wypełnia się bufor wejściowy. To szalone ...
Willy Tarreau
6
Jeff, to nie jest trzy razy. tcp_mem jest na stronach i określa globalny rozmiar. tcp_rmem i tcp_wmem są w bajtach i określają rozmiar poszczególnych gniazd.
Willy Tarreau
Te elementy dostrajające wyglądają niepoprawnie, w przypadku współbieżnych serwerów z małymi danymi nie chcesz rezerwować tylu buforów gniazd, a tcp_mem jest zupełnie inny niż r / wmem, używanie tych samych liczb nie ma sensu (jeden bajt na połączenie, drugi stron na system)
eckes