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/sockstat
jest 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 EAGAIN
odpowiedziami, recvmsg
a następnie przejściem do ENOBUFS
powrotu 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ć tcpdump
maszynę, 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
tcpdump
z-p/--no-promiscuous-mode
flagą nie usuwa licznika używanych gniazd i przywraca maszynę do stanu używalności. - Uruchomienie
ifconfig eth0 txqueuelen 1001
resetuje licznik używanych gniazd, ale łączność nie jest przywracana. - Ręczne ustawienie trybu promis
ip link set eth0 promisc on
również nie przywraca łączności.net.ipv4.xfrm4_gc_thresh
jest ustawiony na 32768, a jego nieznaczne zwiększenie nie rozwiązuje problemu.
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