Klaster Elasticsearch 200 TB+

Klaster Elasticsearch 200 TB+

Wiele osób ma problemy z Elasticsearch. Ale co się stanie, gdy zechcesz go użyć do przechowywania kłód „w szczególnie dużej objętości”? I czy bezbolesna jest także awaria któregoś z kilku centrów danych? Jaką architekturę powinieneś stworzyć i na jakie pułapki się natkniesz?

W Odnoklassnikach postanowiliśmy użyć Elasticsearch do rozwiązania problemu zarządzania logami i teraz dzielimy się z Habr naszymi doświadczeniami: zarówno dotyczącymi architektury, jak i pułapek.

Nazywam się Piotr Zajcew, pracuję jako administrator systemu w Odnoklassnikach. Wcześniej byłem także administratorem, pracowałem z Manticore Search, Sphinx search, Elasticsearch. Być może, jeśli pojawi się kolejne...wyszukiwanie, prawdopodobnie też z nim popracuję. Na zasadzie wolontariatu biorę także udział w szeregu projektów open source.

Kiedy przyjechałem do Odnoklassniki, lekkomyślnie powiedziałem na rozmowie kwalifikacyjnej, że mogę współpracować z Elasticsearch. Kiedy oswoiłem się z tym i wykonałem kilka prostych zadań, powierzono mi duże zadanie zreformowania istniejącego wówczas systemu zarządzania logami.

Wymagania

Wymagania systemowe zostały sformułowane w następujący sposób:

  • Jako frontend miał służyć Graylog. Ponieważ firma miała już doświadczenie w korzystaniu z tego produktu, programiści i testerzy o tym wiedzieli, było to dla nich znajome i wygodne.
  • Objętość danych: średnio 50-80 tysięcy wiadomości na sekundę, ale jeśli coś się zepsuje, to ruch nie jest niczym ograniczony, może wynosić 2-3 miliony linii na sekundę
  • Po omówieniu z klientami wymagań dotyczących szybkości przetwarzania zapytań zdaliśmy sobie sprawę, że typowy schemat korzystania z takiego systemu jest następujący: ludzie szukają logów swojej aplikacji z ostatnich dwóch dni i nie chcą czekać dłużej niż godzinę drugi dla wyniku sformułowanego zapytania.
  • Administratorzy nalegali, aby w razie potrzeby system był łatwo skalowalny, bez konieczności zagłębiania się w jego działanie.
  • Zatem jedynym zadaniem konserwacyjnym, jakiego wymagają okresowo te systemy, jest wymiana części sprzętu.
  • Ponadto Odnoklassniki mają doskonałą tradycję techniczną: każda usługa, którą uruchamiamy, musi przetrwać awarię centrum danych (nagłą, nieplanowaną i absolutnie w każdej chwili).

Najwięcej nas kosztowało ostatnie wymaganie w realizacji tego projektu, o czym opowiem bardziej szczegółowo.

Środę

Pracujemy w czterech centrach danych, podczas gdy węzły danych Elasticsearch mogą być zlokalizowane tylko w trzech (z wielu powodów nietechnicznych).

Te cztery centra danych zawierają około 18 tysięcy różnych źródeł logów – sprzęt, kontenery, maszyny wirtualne.

Ważna funkcja: klaster zaczyna się w kontenerach Podman nie na maszynach fizycznych, ale na własny produkt chmurowy one-Cloud. Kontenery mają gwarancję 2 rdzeni, podobnie jak w przypadku 2.0 Ghz v4, z możliwością recyklingu pozostałych rdzeni, jeśli są bezczynne.

Innymi słowy:

Klaster Elasticsearch 200 TB+

Topologia

Początkowo widziałem ogólną formę rozwiązania w następujący sposób:

  • Za rekordem A domeny Graylog znajdują się 3-4 VIP-y, jest to adres, na który wysyłane są logi.
  • każdy VIP jest balanserem LVS.
  • Następnie logi trafiają do baterii Graylog, część danych jest w formacie GELF, część w formacie syslog.
  • Następnie wszystko to jest zapisywane w dużych partiach do zespołu koordynatorów Elasticsearch.
  • A one z kolei wysyłają żądania zapisu i odczytu do odpowiednich węzłów danych.

Klaster Elasticsearch 200 TB+

terminologia

Być może nie wszyscy rozumieją szczegółowo terminologię, dlatego chciałbym się nad nią trochę zatrzymać.

Elasticsearch ma kilka typów węzłów - główny, koordynator, węzeł danych. Istnieją dwa inne typy różnych transformacji dzienników i komunikacji między różnymi klastrami, ale użyliśmy tylko tych wymienionych.

Mistrz
Wysyła polecenie ping do wszystkich węzłów znajdujących się w klastrze, utrzymuje aktualną mapę klastra i rozprowadza ją pomiędzy węzłami, przetwarza logikę zdarzeń i wykonuje różne rodzaje porządkowania całego klastra.

Koordynator
Wykonuje jedno zadanie: akceptuje żądania odczytu lub zapisu od klientów i kieruje ten ruch. W przypadku żądania zapisu najprawdopodobniej zapyta mastera, w którym fragmencie odpowiedniego indeksu powinien go umieścić, i przekieruje żądanie dalej.

Węzeł danych
Przechowuje dane, realizuje zapytania przychodzące z zewnątrz oraz wykonuje operacje na znajdujących się na nich shardach.

graylog
To coś w rodzaju fuzji Kibany z Logstashem w stosie ELK. Graylog łączy w sobie zarówno interfejs użytkownika, jak i potok przetwarzania dziennika. Pod maską Graylog uruchamia Kafkę i Zookeeper, które zapewniają łączność z Graylog jako klastrem. Graylog może buforować logi (Kafka) w przypadku, gdy Elasticsearch jest niedostępny i powtarzać nieudane żądania odczytu i zapisu, grupować i oznaczać logi zgodnie z określonymi regułami. Podobnie jak Logstash, Graylog ma funkcję modyfikowania wierszy przed zapisaniem ich w Elasticsearch.

Dodatkowo Graylog posiada wbudowaną funkcję wykrywania usług, która pozwala w oparciu o jeden dostępny węzeł Elasticsearch pozyskać całą mapę klastrów i przefiltrować ją po konkretnym tagu, co umożliwia kierowanie żądań do konkretnych kontenerów.

Wizualnie wygląda to mniej więcej tak:

Klaster Elasticsearch 200 TB+

To jest zrzut ekranu z konkretnej instancji. Tutaj budujemy histogram na podstawie wyszukiwanego hasła i wyświetlamy odpowiednie wiersze.

wskaźniki

Wracając do architektury systemu, chciałbym bardziej szczegółowo opisać, w jaki sposób zbudowaliśmy model indeksu, aby wszystko działało poprawnie.

Na powyższym diagramie jest to najniższy poziom: węzły danych Elasticsearch.

Indeks to duża wirtualna jednostka złożona z fragmentów Elasticsearch. Sam w sobie każdy z fragmentów jest niczym więcej niż indeksem Lucene. Z kolei każdy indeks Lucene składa się z jednego lub więcej segmentów.

Klaster Elasticsearch 200 TB+

Projektując uznaliśmy, że aby spełnić wymagania dotyczące szybkości odczytu dużej ilości danych, musimy „rozłożyć” te dane równomiernie pomiędzy węzłami danych.

Skutkowało to tym, że liczba shardów na indeks (z replikami) powinna być ściśle równa liczbie węzłów danych. Po pierwsze, aby zapewnić współczynnik replikacji równy dwa (czyli możemy stracić połowę klastra). Po drugie, w celu przetworzenia żądań odczytu i zapisu na co najmniej połowie klastra.

Najpierw określiliśmy czas przechowywania na 30 dni.

Rozkład fragmentów można przedstawić graficznie w następujący sposób:

Klaster Elasticsearch 200 TB+

Cały ciemnoszary prostokąt to indeks. Lewy czerwony kwadrat to podstawowy fragment, pierwszy w indeksie. A niebieski kwadrat to odłamek repliki. Znajdują się one w różnych centrach danych.

Gdy dodamy kolejny fragment, trafia on do trzeciego centrum danych. I ostatecznie otrzymujemy taką strukturę, która umożliwia utratę DC bez utraty spójności danych:

Klaster Elasticsearch 200 TB+

Rotacja indeksów, tj. tworząc nowy indeks i usuwając najstarszy, ustaliliśmy, że będzie on równy 48 godzinom (zgodnie ze schematem wykorzystania indeksu: najczęściej przeszukiwane są ostatnie 48 godzin).

Ten odstęp rotacji indeksu wynika z następujących powodów:

Gdy żądanie wyszukiwania dociera do określonego węzła danych, wówczas z punktu widzenia wydajności bardziej opłacalne jest przeszukiwanie jednego fragmentu, jeśli jego rozmiar jest porównywalny z rozmiarem biodra węzła. Pozwala to zachować „gorącą” część indeksu na stercie i szybko uzyskać do niej dostęp. Gdy jest dużo „gorących części”, prędkość wyszukiwania indeksu spada.

Kiedy węzeł rozpoczyna wykonywanie zapytania wyszukiwania na jednym fragmencie, przydziela liczbę wątków równą liczbie rdzeni hiperwątkowych maszyny fizycznej. Jeśli zapytanie dotyczy dużej liczby fragmentów, liczba wątków rośnie proporcjonalnie. Ma to negatywny wpływ na szybkość wyszukiwania i negatywnie wpływa na indeksowanie nowych danych.

Aby zapewnić niezbędne opóźnienie wyszukiwania, zdecydowaliśmy się użyć dysku SSD. Aby szybko przetwarzać żądania, maszyny hostujące te kontenery musiały mieć co najmniej 56 rdzeni. Jako warunkowo wystarczającą wartość określającą liczbę wątków, które Elasticsearch wygeneruje podczas działania, wybrano liczbę 56. W Elasitcsearch wiele parametrów puli wątków zależy bezpośrednio od liczby dostępnych rdzeni, co z kolei bezpośrednio wpływa na wymaganą liczbę węzłów w klastrze zgodnie z zasadą „mniej rdzeni – więcej węzłów”.

W rezultacie odkryliśmy, że średnio odłamek waży około 20 gigabajtów, a na indeks przypada 1 odłamków. Odpowiednio, jeśli będziemy je obracać raz na 360 godzin, wówczas będziemy mieli ich 48. Każdy indeks zawiera dane za 15 dni.

Obwody zapisu i odczytu danych

Zastanówmy się, jak dane są rejestrowane w tym systemie.

Załóżmy, że do koordynatora dotarła prośba od Graylog. Przykładowo chcemy zaindeksować 2-3 tysiące wierszy.

Koordynator po otrzymaniu prośby od Grayloga zadaje mistrzowi pytanie: „W żądaniu indeksowania wyraźnie określiliśmy indeks, ale nie określono, w którym fragmencie go zapisać”.

Master odpowiada: „Zapisz tę informację do fragmentu nr 71”, po czym jest ona wysyłana bezpośrednio do odpowiedniego węzła danych, gdzie znajduje się fragment podstawowy nr 71.

Następnie dziennik transakcji jest replikowany do fragmentu repliki, który znajduje się w innym centrum danych.

Klaster Elasticsearch 200 TB+

Żądanie wyszukiwania przychodzi z Graylog do koordynatora. Koordynator przekierowuje go zgodnie z indeksem, podczas gdy Elasticsearch rozdziela żądania pomiędzy fragmentem podstawowym i fragmentem repliki, stosując zasadę działania okrężnego.

Klaster Elasticsearch 200 TB+

180 węzłów reaguje nierównomiernie i w trakcie tej reakcji koordynator gromadzi informacje, które zostały już „wyplute” przez szybsze węzły danych. Następnie, gdy zostaną dostarczone wszystkie informacje lub upłynął limit czasu żądania, przekazuje wszystko bezpośrednio klientowi.

Cały ten system przetwarza zapytania z ostatnich 48 godzin średnio w ciągu 300–400 ms, z wyłączeniem zapytań z wiodącym symbolem wieloznacznym.

Kwiaty z Elasticsearch: konfiguracja Java

Klaster Elasticsearch 200 TB+

Aby wszystko działało tak, jak pierwotnie chcieliśmy, spędziliśmy bardzo dużo czasu na debugowaniu wielu różnych rzeczy w klastrze.

Pierwsza część wykrytych problemów była związana ze sposobem, w jaki Java jest domyślnie wstępnie skonfigurowana w Elasticsearch.

Problem pierwszy
Zaobserwowaliśmy bardzo dużą liczbę raportów, że na poziomie Lucene, gdy działają zadania w tle, łączenie segmentów Lucene kończy się niepowodzeniem i kończy się błędem. Jednocześnie w logach było jasne, że był to błąd OutOfMemoryError. Z telemetrii widzieliśmy, że biodro było wolne i nie było jasne, dlaczego operacja się nie powiodła.

Okazało się, że scalanie indeksu Lucene następuje poza biodrem. A kontenery są dość ściśle ograniczone pod względem zużywanych zasobów. Do tych zasobów zmieściła się tylko sterta (wartość sterty.size była w przybliżeniu równa pamięci RAM), a niektóre operacje poza stertą ulegały awarii z powodu błędu alokacji pamięci, jeśli z jakiegoś powodu nie mieściły się w ~500MB pozostałych przed limitem.

Poprawka była dość banalna: zwiększono ilość pamięci RAM dostępnej dla kontenera, po czym zapomnieliśmy, że w ogóle mieliśmy takie problemy.

Problem drugi
4-5 dni po uruchomieniu klastra zauważyliśmy, że węzły danych zaczęły okresowo wypadać z klastra i wchodzić do niego po 10-20 sekundach.

Kiedy zaczęliśmy to rozmyślać, okazało się, że ta pamięć poza stertą w Elasticsearch nie jest w żaden sposób kontrolowana. Kiedy daliśmy kontenerowi więcej pamięci, mogliśmy wypełnić bezpośrednie pule buforów różnymi informacjami, co zostało wyczyszczone dopiero po uruchomieniu jawnego GC z Elasticsearch.

W niektórych przypadkach operacja ta trwała dość długo i w tym czasie klaster zdążył oznaczyć ten węzeł jako już zakończony. Ten problem jest dobrze opisany tutaj.

Rozwiązanie było następujące: ograniczyliśmy możliwość wykorzystania przez Javę większości pamięci poza stertą do tych operacji. Ograniczyliśmy go do 16 gigabajtów (-XX:MaxDirectMemorySize=16g), zapewniając, że jawne GC było wywoływane znacznie częściej i przetwarzane znacznie szybciej, dzięki czemu nie destabilizowało już klastra.

Problem trzeci
Jeśli myślisz, że skończyły się problemy z „węzłami opuszczającymi klaster w najbardziej nieoczekiwanym momencie”, to się mylisz.

Kiedy konfigurowaliśmy pracę z indeksami, wybraliśmy mmapfs skrócić czas wyszukiwania na świeżych odłamkach z doskonałą segmentacją. Było to sporym błędem, gdyż przy użyciu mmapfs plik jest mapowany do RAM-u, a następnie pracujemy z zamapowanym plikiem. Przez to okazuje się, że gdy GC próbuje zatrzymać wątki w aplikacji, na bardzo długi czas wchodzimy do bezpiecznego punktu, a w drodze do niego aplikacja przestaje odpowiadać na zapytania mastera o to, czy żyje . W związku z tym master uważa, że ​​węzeł nie jest już obecny w klastrze. Następnie po 5-10 sekundach moduł zbierający elementy bezużyteczne działa, węzeł ożywa, ponownie wchodzi do klastra i zaczyna inicjować shardy. Całość bardzo przypominała „produkcję, na którą zasłużyliśmy” i nie nadawała się do niczego poważnego.

Aby pozbyć się tego zachowania, najpierw przeszliśmy na standardowe niofy, a następnie, kiedy migrowaliśmy z piątej wersji Elastic do szóstej, wypróbowaliśmy Hybridfs, gdzie ten problem nie został odtworzony. Możesz przeczytać więcej o typach przechowywania tutaj.

Problem czwarty
Następnie pojawił się kolejny bardzo interesujący problem, którym zajmowaliśmy się w rekordowym czasie. Złapaliśmy go na 2-3 miesiące, bo jego wzór był zupełnie niezrozumiały.

Czasami nasi koordynatorzy jeździli do Full GC, zwykle jakiś czas po obiedzie, i nigdy stamtąd nie wracali. Jednocześnie przy logowaniu opóźnienia GC wyglądało to tak: wszystko idzie dobrze, dobrze, dobrze, a potem nagle wszystko idzie bardzo źle.

Na początku myśleliśmy, że mamy złego użytkownika, który uruchamia jakieś żądanie, które wytrąca koordynatora z trybu pracy. Rejestrowaliśmy żądania przez bardzo długi czas, próbując dowiedzieć się, co się dzieje.

W rezultacie okazało się, że w momencie, gdy użytkownik uruchamia ogromne żądanie, które trafia do konkretnego koordynatora Elasticsearch, niektóre węzły odpowiadają dłużej niż inne.

I podczas gdy koordynator czeka na odpowiedź ze wszystkich węzłów, gromadzi wyniki przesłane z węzłów, które już odpowiedziały. W przypadku GC oznacza to, że nasze wzorce wykorzystania sterty zmieniają się bardzo szybko. A GC, którego używaliśmy, nie poradziło sobie z tym zadaniem.

Jedynym rozwiązaniem, które znaleźliśmy, które zmienia zachowanie klastra w tej sytuacji, jest migracja do JDK13 i użycie modułu zbierającego elementy bezużyteczne Shenandoah. To rozwiązało problem, nasi koordynatorzy przestali spadać.

Tutaj skończyły się problemy z Javą i zaczęły się problemy z przepustowością.

„Jagody” z Elasticsearch: przepustowość

Klaster Elasticsearch 200 TB+

Problemy z przepustowością powodują, że nasz klaster działa stabilnie, jednak w szczytowych momentach liczby indeksowanych dokumentów i podczas manewrów wydajność jest niewystarczająca.

Pierwszy napotkany objaw: podczas niektórych „eksplozji” w produkcji, gdy nagle generowana jest bardzo duża liczba logów, w Graylog zaczyna często migać błąd indeksowania es_rejected_execution.

Wynikało to z faktu, że thread_pool.write.queue na jednym węźle danych, do momentu, gdy Elasticsearch będzie w stanie przetworzyć żądanie indeksowania i przesłać informacje na shard na dysku, jest w stanie domyślnie buforować tylko 200 żądań. I w Dokumentacja Elasticsearch Niewiele mówi się o tym parametrze. Wskazana jest tylko maksymalna liczba wątków i domyślny rozmiar.

Oczywiście poszliśmy przekręcić tę wartość i dowiedzieliśmy się, co następuje: w szczególności w naszej konfiguracji do 300 żądań jest całkiem dobrze buforowanych, a wyższa wartość jest obarczona faktem, że ponownie lecimy do Full GC.

Ponadto, ponieważ są to partie wiadomości, które docierają w ramach jednego żądania, konieczne było ulepszenie Grayloga, aby zapisywał nie często i w małych partiach, ale w dużych partiach lub raz na 3 sekundy, jeśli partia nie jest jeszcze ukończona. W tym przypadku okazuje się, że informacja, którą zapiszemy w Elasticsearch, staje się dostępna nie w dwie sekundy, a w pięć (co nam całkiem odpowiada), ale ilość powtórzeń, jakie trzeba wykonać, aby przecisnąć się przez dużą stos informacji jest zmniejszony.

Jest to szczególnie ważne w tych momentach, gdy coś gdzieś się zawiesiło i wściekle o tym informuje, aby nie dostać całkowicie zaspamowanego Elastica, a po pewnym czasie - węzłów Graylog, które nie działają z powodu zatkanych buforów.

Ponadto, kiedy mieliśmy te same eksplozje w produkcji, otrzymaliśmy skargi od programistów i testerów: w momencie, gdy naprawdę potrzebowali tych logów, otrzymywali je bardzo powoli.

Zaczęli to sobie wyobrażać. Z jednej strony było jasne, że zarówno zapytania wyszukiwania, jak i zapytania indeksujące były przetwarzane zasadniczo na tych samych maszynach fizycznych, co w ten czy inny sposób powodowało pewne straty.

Można to jednak częściowo obejść, ponieważ w szóstych wersjach Elasticsearch pojawił się algorytm pozwalający na dystrybucję zapytań pomiędzy odpowiednimi węzłami danych nie według zasady losowego działania okrężnego (kontener indeksujący i przechowujący podstawowy -shard może być bardzo zajęty, nie będzie możliwości szybkiej odpowiedzi), ale przekazać to żądanie do mniej obciążonego kontenera za pomocą repliki-sharda, który odpowie znacznie szybciej. Innymi słowy, dotarliśmy do use_adaptive_replica_selection: true.

Czytelniczy obraz zaczyna wyglądać następująco:

Klaster Elasticsearch 200 TB+

Przejście na ten algorytm umożliwiło znaczne skrócenie czasu wykonywania zapytań w momentach, gdy mieliśmy duży przepływ logów do zapisania.

Wreszcie głównym problemem było bezbolesne usunięcie centrum danych.

Czego oczekiwaliśmy od klastra zaraz po utracie połączenia z jednym DC:

  • Jeśli w uszkodzonym centrum danych mamy bieżącego mistrza, zostanie on ponownie wybrany i przeniesiony jako rola do innego węzła w innym kontrolerze domeny.
  • Master szybko usunie wszystkie niedostępne węzły z klastra.
  • Na podstawie pozostałych zrozumie: w utraconym data center mieliśmy takie a takie pierwotne shardy, w pozostałych data center szybko wypromuje komplementarne repliki shardów, a my będziemy kontynuować indeksowanie danych.
  • W rezultacie przepustowość zapisu i odczytu klastra będzie stopniowo spadać, ale ogólnie wszystko będzie działać, choć powoli, ale stabilnie.

Okazało się, że chcieliśmy coś takiego:

Klaster Elasticsearch 200 TB+

I otrzymaliśmy co następuje:

Klaster Elasticsearch 200 TB+

Jak to się stało?

Kiedy centrum danych upadło, nasz mistrz stał się wąskim gardłem.

Dlaczego?

Faktem jest, że master ma TaskBatcher, który jest odpowiedzialny za dystrybucję niektórych zadań i zdarzeń w klastrze. Każde wyjście z węzła, jakikolwiek awans sharda z repliki do podstawowego, każde zadanie polegające na utworzeniu gdzieś sharda – wszystko to trafia najpierw do TaskBatcher, gdzie jest przetwarzane sekwencyjnie i w jednym wątku.

W momencie wycofania jednego centrum danych okazało się, że wszystkie węzły danych w pozostałych centrach danych uznały za swój obowiązek poinformować mistrza „straciliśmy takie a takie odłamki i takie a takie węzły danych”.

W tym samym czasie pozostałe węzły danych wysłały wszystkie te informacje do obecnego mistrza i próbowały poczekać na potwierdzenie, że je zaakceptował. Nie czekali na to, ponieważ mistrz otrzymywał zadania szybciej, niż był w stanie odpowiedzieć. Węzły przekroczyły limit czasu powtarzających się żądań, a master w tym momencie nawet nie próbował na nie odpowiedzieć, ale był całkowicie pochłonięty zadaniem sortowania żądań według priorytetów.

W formie terminala okazało się, że węzły danych spamowały mastera do tego stopnia, że ​​przeszedł on w pełne GC. Potem nasza rola mastera przeniosła się do jakiegoś kolejnego węzła, stało się z nim absolutnie to samo i w rezultacie klaster całkowicie się rozpadł.

Dokonaliśmy pomiarów i przed wersją 6.4.0, w której zostało to naprawione, wystarczyło nam jednocześnie wyprowadzić tylko 10 węzłów danych z 360, aby całkowicie zamknąć klaster.

Wyglądało to mniej więcej tak:

Klaster Elasticsearch 200 TB+

Po wersji 6.4.0, w której naprawiono ten straszny błąd, węzły danych przestały zabijać master. Ale to nie uczyniło go „mądrzejszym”. Mianowicie: kiedy wyprowadzamy 2, 3 lub 10 (dowolną liczbę inną niż jeden) węzłów danych, master otrzymuje pierwszą wiadomość, która mówi, że węzeł A opuścił i próbuje poinformować o tym węzeł B, węzeł C, węzeł D.

A na chwilę obecną można temu zaradzić jedynie poprzez ustawienie limitu czasu dla prób poinformowania kogoś o czymś, równego około 20-30 sekund i w ten sposób kontrolowania szybkości wychodzenia centrum danych z klastra.

W zasadzie mieści się to w wymaganiach, jakie początkowo postawiono produktowi końcowemu w ramach projektu, jednak z punktu widzenia „czystej nauki” jest to błąd. Co, nawiasem mówiąc, zostało pomyślnie naprawione przez programistów w wersji 7.2.

Co więcej, gdy wysiadł dany węzeł danych, okazało się, że ważniejsze było rozpowszechnienie informacji o jego wyjściu, niż poinformowanie całego klastra, że ​​znajdują się na nim takie a takie pierwotne-shardy (w celu wypromowania repliki-sharda w innym danych centrum w szkole podstawowej i można było na nich zapisać informacje).

Dlatego też, gdy wszystko już ucichło, zwolnione węzły danych nie są od razu oznaczane jako nieaktualne. W związku z tym jesteśmy zmuszeni poczekać, aż upłynie limit czasu wszystkich pingów do uwolnionych węzłów danych i dopiero wtedy nasz klaster zaczyna nam informować, że tam, tam i tam musimy kontynuować rejestrowanie informacji. Możesz przeczytać więcej na ten temat tutaj.

Dzięki temu operacja wycofania centrum danych zajmuje nam dzisiaj w godzinach szczytu około 5 minut. Jak na tak dużego i nieporadnego kolosa jest to całkiem niezły wynik.

W rezultacie podjęliśmy następującą decyzję:

  • Mamy 360 węzłów danych z dyskami o pojemności 700 gigabajtów.
  • 60 koordynatorów kierujących ruchem przez te same węzły danych.
  • 40 masterów, które pozostawiliśmy jako swego rodzaju dziedzictwo od wersji wcześniejszych niż 6.4.0 — aby przetrwać wycofanie centrum danych, byliśmy psychicznie przygotowani na utratę kilku maszyn, aby mieć pewność kworum masterów nawet w najgorszy scenariusz
  • Wszelkie próby łączenia ról na jednym kontenerze kończyły się tym, że prędzej czy później węzeł pęknie pod obciążeniem.
  • Cały klaster wykorzystuje stertę o rozmiarze 31 gigabajtów: wszystkie próby zmniejszenia rozmiaru kończyły się albo zabijaniem niektórych węzłów w przypadku intensywnych zapytań wyszukiwania z wiodącym symbolem wieloznacznym, albo uruchamianiem wyłącznika w samym Elasticsearch.
  • Dodatkowo, aby zapewnić wydajność wyszukiwania, staraliśmy się, aby liczba obiektów w klastrze była jak najmniejsza, aby przetworzyć jak najmniej zdarzeń w wąskim gardle, które znaleźliśmy w masterze.

Na koniec o monitorowaniu

Aby mieć pewność, że wszystko działa zgodnie z oczekiwaniami, monitorujemy następujące elementy:

  • Każdy węzeł danych raportuje naszej chmurze, że istnieje i znajdują się na nim takie a takie shardy. Kiedy coś gdzieś gasimy, klaster po 2-3 sekundach melduje, że w centrum A wygasiliśmy węzły 2, 3 i 4 - oznacza to, że w innych data center pod żadnym pozorem nie możemy wygasić tych węzłów, na których jest tylko jeden shard lewy.
  • Znając charakter zachowania mistrza, bardzo uważnie przyglądamy się liczbie oczekujących zadań. Bo nawet jedno zablokowane zadanie, jeśli nie upłynie w odpowiednim czasie, teoretycznie w jakiejś awaryjnej sytuacji może stać się przyczyną, dla której np. promocja repliki sharda w podstawowym nie zadziała, przez co indeksowanie przestanie działać.
  • Bardzo uważnie przyglądamy się także opóźnieniom modułu zbierającego elementy bezużyteczne, ponieważ mieliśmy już z tym duże trudności podczas optymalizacji.
  • Odrzuca według wątku, aby z wyprzedzeniem zrozumieć, gdzie znajduje się wąskie gardło.
  • Cóż, standardowe metryki, takie jak sterta, pamięć RAM i we/wy.

Budując monitorowanie, musisz wziąć pod uwagę funkcje puli wątków w Elasticsearch. Dokumentacja Elasticsearch opisuje opcje konfiguracyjne i domyślne wartości wyszukiwania i indeksowania, natomiast zupełnie milczy na temat thread_pool.management.Wątki te przetwarzają w szczególności zapytania typu _cat/shards i inne podobne, które są wygodne w użyciu podczas pisania monitoringu. Im większy klaster, tym więcej takich żądań jest wykonywanych w jednostce czasu, a wspomniany wcześniej thread_pool.management nie tylko nie jest prezentowany w oficjalnej dokumentacji, ale także jest domyślnie ograniczony do 5 wątków, co jest bardzo szybko usuwane po który monitoring przestaje działać prawidłowo.

Co chcę powiedzieć na zakończenie: udało się! Udało nam się dać naszym programistom i deweloperom narzędzie, które w niemal każdej sytuacji może szybko i rzetelnie dostarczyć informację o tym, co dzieje się na produkcji.

Tak, okazało się to dość skomplikowane, ale mimo to udało nam się dopasować nasze życzenia do istniejących produktów, których nie musieliśmy sami łatać i przepisywać.

Klaster Elasticsearch 200 TB+

Źródło: www.habr.com

Dodaj komentarz