CoreOS: tcpdump w tajemniczy sposób rozwiązuje problem z siecią (nadmierna liczba używanych gniazd)

14

Mam dziś dla ciebie tajemnicę. Na platformie Azure prowadzimy mały, trzy węzłowy klaster Elasticsearch oparty na CoreOS (2023.5.0 / Linux 4.19.25-coreos). Elasticsearch jest uruchamiany w kontenerze dokera w trybie sieci hosta. Po prawie prawie bezobsługowym działaniu od ponad roku obserwujemy, jak maszyny wchodzą w bardzo interesujący stan.

Aktualizacja

Ten problem został rozwiązany przez poprawkę sterownika w jądrze systemu Linux . Zobacz odpowiedź poniżej.

Objawy

Zasadniczo sieć między dotkniętym komputerem a pozostałymi dwoma węzłami umiera. Wszystkie są w tej samej sieci wirtualnej i tej samej podsieci i mogą zwyczajowo komunikować się ze wszystkimi innymi. Dotknięty węzeł może być nadal dostępny z innych podsieci (mogę w nim ssh) i z innej sprawdzonej sieci wirtualnej. Maszyna ma również (bardzo nierówne) połączenie z Internetem, ale większość żądań po prostu kończy się.

Zauważyliśmy, że w węźle dotkniętym problemem liczba zgłoszonych „gniazd” /proc/net/sockstatjest bardzo wysoka (~ 4,5 k zamiast ~ 300 w zdrowym węźle). Monitorowanie pokazuje, że liczba ta gwałtownie rośnie od momentu, gdy węzeł stanie się niedostępny.

Zabawne jest to, że nie możemy zidentyfikować źródła tych używanych gniazd:

# cat /proc/net/sockstat
sockets: used 4566
TCP: inuse 2 orphan 0 tw 2 alloc 98 mem 4
UDP: inuse 1 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

# cat /proc/net/sockstat6
TCP6: inuse 98
UDP6: inuse 1
UDPLITE6: inuse 0
RAW6: inuse 1
FRAG6: inuse 0 memory 0

Poza tym maszyna wydaje się w porządku. Nie działają żadne podejrzane procesy, użycie procesora jest minimalne, a ilość dostępnej pamięci jest duża.

Pingowanie „nieosiągalnej” maszyny wirtualnej w tej samej podsieci skutkuje kilkoma EAGAINodpowiedziami, recvmsga następnie przejściem do ENOBUFSpowrotu sendmsg. Strace ping wyjściowy tutaj

Zebrałem dodatkowe dane wyjściowe (przed wprowadzeniem jakichkolwiek modyfikacji w systemie) i opublikowałem je w tej liście: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c

Analiza

Próbowaliśmy zamknąć wszystko, co możemy wymyślić na serwerze, a elasticsearch jest pierwszym podejrzanym. Ale zamknięcie pojemnika elasticsearch nie zwalnia zużytych gniazd. To samo dotyczy wszystkich procesów związanych z CoreOS (silnik aktualizacji, locksmithd, ...), a nawet całego środowiska wykonawczego Docker lub rzeczy specyficznych dla platformy Azure. Wydawało się, że nic nie pomaga.

Ale teraz robi się jeszcze dziwniej: próbowaliśmy uruchomić tcpdumpmaszynę, aby zobaczyć, co się dzieje. I oto: problem sam się rozwiązał, przywrócono łączność. Naszą teorią było to, że tcpdump wykonuje pewnego rodzaju syscall, który to rozwiązuje. Uruchomiliśmy tcpdump z gdb i ustawiliśmy punkty przerwania dla wszystkich wywołań systemowych. Po przejściu przez wiele punktów przerwania, w końcu odkryliśmy, że ustawianie trybu promisującego na gnieździe przechwytującym (szczególnie ta linia w libpcap ) jest rzeczą, która resetuje licznik używanych gniazd i przywraca nas do normalnego stanu.

Dodatkowe ustalenia

  • Sprawdziliśmy, że uruchomienie tcpdumpz -p/--no-promiscuous-modeflagą nie usuwa licznika używanych gniazd i przywraca maszynę do stanu używalności.
  • Uruchomienie ifconfig eth0 txqueuelen 1001resetuje licznik używanych gniazd, ale łączność nie jest przywracana.
  • Ręczne ustawienie trybu promis ip link set eth0 promisc onrównież nie przywraca łączności.
    • net.ipv4.xfrm4_gc_thresh jest ustawiony na 32768, a jego nieznaczne zwiększenie nie rozwiązuje problemu.

używane gniazda

Jesteśmy w kontakcie z Azure, które są tak samo zaskoczone jak my. Rozumiem, że to prawdopodobnie nie jest problem, ale tylko objaw. Ale to jedyna namacalna rzecz, jaką do tej pory znalazłem. Mam nadzieję, że dzięki zrozumieniu symptomu mogę zbliżyć się do pierwotnej przyczyny. Interfejsy sieciowe na platformie Azure są uruchamiane przy użyciu tego sterownika sieciowego .

Może winę ponosi CoreOS / Kernel?

Z punktu widzenia osi czasu problemy zaczęły się 11.03.2019, czyli w dniu, w którym CoreOS automatycznie zaktualizował się do najnowszej wersji. Zgodnie z informacjami o wersji ta aktualizacja zawierała aktualizację jądra z 4.15.23 do 4.19.25 . Nadal przeglądam dzienniki zmian, aby sprawdzić, czy coś może tam stanowić problem. Do tej pory odkryłem tylko, że sterownik sieci hyperv otrzymał w ostatnich miesiącach sporo aktualizacji , z których nie wszystkie wydają się być częścią 4.19.25. Zestaw poprawek zastosowany przez CoreOS w 4.19.25 nie jest aż tak imponujący , ale łatka wprowadzająca fałszywy moduł nf_conntrack_ipv4 jest nowa.

Aktualizacja: Możliwa powiązana przychodząca łata do jądra?

Wsparcie!

Jak dotąd mamy następujące pytania:

  • Co może spowodować, że ten wskaźnik „wykorzystanych gniazd” gwałtownie wzrośnie? Przeczytałem źródła jądra dla tej metryki i wydaje się, że jest to tylko licznik bez odniesienia do tego, jakie to są gniazda lub co je stworzyło.

  • Dlaczego liczba ta wynosi około 4,5 tys.? Który limit by to spowodował?

  • Czy coś istotnego zmieniło się między jądrem 4.14.96 a 4.19.25?

  • Dlaczego setsockopt()wywołanie w libpcap resetuje stan?

Powiązany błąd CoreOS: https://github.com/coreos/bugs/issues/2572

Stephan Klein
źródło
Otwarte gniazda to wynikowy problem, a nie główny problem IMHO. Miałem takie zachowanie w systemie Linux z urządzeniami Macvlan (z ich własnymi adresami MAC) na urządzeniu mostkowym. Ustawienie mostu na promis spowodowało, że urządzenia macvlan działały. Nie znam rdzeni ani lazurów. Problem polega na tym, że podstawowa warstwa nie wie o adresach MAC na wyższych poziomach.
AndreasM,
Dziękuję za Twój komentarz! Zdaję sobie sprawę, że duża liczba używanych gniazd nie jest główną przyczyną, po prostu trzymam się jednej konkretnej rzeczy, którą mogę zidentyfikować jako nienormalną na maszynie.
Stephan Klein
Cześć Stephan. Jakieś wieści? zgłoś 1) Czy funkcja WOL jest włączona? 2) Czy sysctl -w net.ipv4.route.flush = 1 rozwiązuje? 3) Co to jest pamięć podręczna arp w stanie roboczym? w stanie pracy?
Massimo,

Odpowiedzi:

4

Przede wszystkim dziękuję za bardzo dobrze napisane pytanie!

Ponieważ poziom szczegółowości, który opisałeś, jest bardzo wysoki i jesteś już na poziomie gdb, zakładam, że moja odpowiedź nie przyda ci się zbytnio. W każdym razie oto próba:

  • Prawdopodobnie próbowałeś już czegoś takiego ss -aei lsof -n?
  • Czy dmesgzwraca coś interesującego, gdy tak się dzieje?
  • Czy używasz iptables na serwerze?
  • Jeśli ustawisz tryb rozwiązły w inny sposób niż tcpdump (powiedzmy ip link set [interface] promisc on), czy to również rozwiąże problem?
  • Czy sprawdziłeś podejrzane procesy, pliki lub inne dziwne działania? Myślisz tylko, że może jakiś nieprzyjemny, nieprzyjemny proces czai się w cieniu, chowając się, i milczy, gdy ustawiony jest tryb rozwiązły?
  • Jeśli pozostawisz tcpdump działający w tle, czy ten problem powróci?

Mam nadzieję, że to pomoże.

Janne Pikkarainen
źródło
1
Dziękuję za odpowiedź! Rzeczywiście zebrałem dane wyjściowe niektórych poleceń, do których się odwołujesz. Są one również powiązane w pytaniu ( gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c ). Najdziwniejsze jest to, że get sposób mniej gniazd zgłosiły ss, lsofa netstatnie z „gniazd używanych” w /proc/net/sockstat. Tylko całkowita liczba (która wydaje się po prostu odczytana z tego pliku) jest taka sama. iptablesdziała, ale nie ma specjalnych zasad (patrz gist), nie próbowałem sam ustawiać trybu promis lub ciągłego uruchamiania tcpdump. Zrobię to następnym razem.
Stephan Klein
Dodałem dane wyjściowe ss -aepido mojej kolekcji danych wyjściowych: gist.github.com/privatwolke/... - Niestety, dmesg nie zwraca dokładnie nic, gdy tak się dzieje. W rzeczywistości ostatni wpis przed incydentem ma 5 dni.
Stephan Klein
Dodano dmesg / journalctl -kwyjście.
Stephan Klein
Sprawdziłem, że ip link set eth0 promisc onsam nie przywraca komputera do stanu używalności.
Stephan Klein
Witaj, czy obejrzałeś już inne pytanie na tej stronie? serverfault.com/questions/614453/… Wygląda na to, że oznacza to, że wyczerpujesz pamięć podręczną xfrm4 dest. Możesz go zwiększyć za pomocą tego ustawienia jądra: xfrm4_gc_thresh - INTEGER The threshold at which we will start garbage collecting for IPv4 destination cache entries. At twice this value the system will refuse new allocations. O ile mogę stwierdzić, że jest to związane z IPsec, ale nie wydaje się, aby tutaj również działał.
Pedro Perez
0

Było to spowodowane błędem w sterowniku hv_netsvc w jądrze Linuksa. Możemy rozwiązać ten problem z programistą Microsoft i udało nam się uzyskać poprawkę zastosowaną wcześniej.

Zacytuję tutaj komunikat zatwierdzenia, ponieważ dość dobrze podsumowuje problem:

Gdy bufor pierścieniowy jest prawie pełny z powodu komunikatów zakończenia RX, pakiet TX może osiągnąć „niski znak wodny” i spowodować zatrzymanie kolejki. Jeśli zakończenie TX nadejdzie wcześniej niż zatrzymanie kolejki, budzenie może zostać pominięte.

Ta łatka przenosi sprawdzenie ostatniego oczekującego pakietu, aby obejmował zarówno EAGAIN, jak i przypadki powodzenia, więc kolejka zostanie w razie potrzeby niezawodnie wybudzona.

Do przyszłego użytku zatwierdzenie, które to naprawia, to https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .

Stephan Klein
źródło