Jak w CIAN ujarzmiliśmy terabajty logów

Jak w CIAN ujarzmiliśmy terabajty logów

Witam wszystkich, mam na imię Aleksander, pracuję w CIAN jako inżynier i zajmuję się administracją systemami oraz automatyzacją procesów infrastrukturalnych. W komentarzach do jednego z poprzednich artykułów zostaliśmy poproszeni o opowiedzenie, skąd pozyskujemy 4 TB logów dziennie i co z nimi robimy. Tak, logów mamy bardzo dużo, a do ich przetwarzania utworzono oddzielny klaster infrastruktury, co pozwala nam na szybkie rozwiązywanie problemów. W tym artykule opowiem o tym, jak na przestrzeni roku dostosowaliśmy go do pracy ze stale rosnącym przepływem danych.

Gdzie zaczęliśmy?

Jak w CIAN ujarzmiliśmy terabajty logów

W ciągu ostatnich kilku lat obciążenie cian.ru wzrosło bardzo szybko i do trzeciego kwartału 2018 roku ruch zasobów osiągnął 11.2 miliona unikalnych użytkowników miesięcznie. W tym czasie w krytycznych momentach straciliśmy nawet 40% logów, dlatego nie mogliśmy szybko uporać się z incydentami i poświęciliśmy dużo czasu i wysiłku na ich rozwiązywanie. Często też nie potrafiliśmy znaleźć przyczyny problemu, który po pewnym czasie powracał. To było piekło i trzeba było coś z tym zrobić.

W tamtym czasie do przechowywania logów używaliśmy klastra 10 węzłów danych z ElasticSearch w wersji 5.5.2 ze standardowymi ustawieniami indeksu. Został wprowadzony ponad rok temu jako rozwiązanie popularne i niedrogie: wtedy przepływ kłód nie był tak duży, nie było sensu wymyślać niestandardowych konfiguracji. 

Przetwarzanie przychodzących logów zostało zapewnione przez Logstash na różnych portach pięciu koordynatorów ElasticSearch. Jeden indeks, niezależnie od rozmiaru, składał się z pięciu fragmentów. Zorganizowano godzinną i dzienną rotację, w efekcie co godzinę w klastrze pojawiało się około 100 nowych odłamków. Choć logów nie było zbyt wiele, klaster radził sobie dobrze i nikt nie zwracał uwagi na jego ustawienia. 

Wyzwania szybkiego wzrostu

Ilość generowanych logów rosła bardzo szybko, gdyż dwa procesy nakładały się na siebie. Z jednej strony wzrosła liczba użytkowników serwisu. Z drugiej strony zaczęliśmy aktywnie przechodzić na architekturę mikroserwisową, odkopując nasze stare monolity w C# i Pythonie. Kilkadziesiąt nowych mikroserwisów, które zastąpiły części monolitu, wygenerowało znacznie więcej logów dla klastra infrastruktury. 

Skalowanie doprowadziło nas do punktu, w którym klaster stał się praktycznie niemożliwy do zarządzania. Kiedy dzienniki zaczęły pojawiać się z szybkością 20 tysięcy wiadomości na sekundę, częsta, bezużyteczna rotacja zwiększyła liczbę fragmentów do 6 tysięcy, a na każdy węzeł przypadało ponad 600 fragmentów. 

Doprowadziło to do problemów z alokacją pamięci RAM, a gdy węzeł uległ awarii, wszystkie shardy zaczęły poruszać się jednocześnie, zwielokrotniając ruch i ładując inne węzły, co prawie uniemożliwiało zapis danych do klastra. I w tym okresie zostaliśmy bez kłód. A jeśli pojawił się problem z serwerem, w zasadzie straciliśmy 1/10 klastra. Duża liczba małych indeksów zwiększała złożoność.

Bez logów nie rozumieliśmy przyczyn zdarzenia i prędzej czy później mogliśmy ponownie wejść na tę samą grabie, co w ideologii naszego zespołu było nie do przyjęcia, ponieważ wszystkie nasze mechanizmy pracy mają na celu coś wręcz odwrotnego - nigdy się nie powtarzają te same problemy. Aby to zrobić, potrzebowaliśmy pełnej liczby logów i ich dostarczania niemal w czasie rzeczywistym, ponieważ zespół dyżurujących inżynierów monitorował alerty nie tylko na podstawie metryk, ale także logów. Aby zrozumieć skalę problemu, w tamtym czasie łączny wolumen logów wynosił około 2 TB dziennie. 

Postawiliśmy sobie za cel całkowite wyeliminowanie strat kłód i skrócenie czasu ich dostarczenia do klastra ELK do maksymalnie 15 minut w przypadku wystąpienia siły wyższej (liczba ta później opierała się na tym jako wewnętrznym KPI).

Nowy mechanizm rotacji i węzły typu „gorące-ciepłe”.

Jak w CIAN ujarzmiliśmy terabajty logów

Konwersję klastra rozpoczęliśmy od aktualizacji wersji ElasticSearch z 5.5.2 do 6.4.3. Po raz kolejny padł nasz klaster w wersji 5, więc postanowiliśmy go wyłączyć i całkowicie zaktualizować - nadal nie ma żadnych logów. Dlatego dokonaliśmy tego przejścia w ciągu zaledwie kilku godzin.

Najbardziej zakrojoną na tym etapie transformacją była implementacja Apache Kafka na trzech węzłach z koordynatorem w roli bufora pośredniego. Broker wiadomości uchronił nas przed utratą logów podczas problemów z ElasticSearch. Jednocześnie dodaliśmy do klastra 2 węzły i przeszliśmy na architekturę typu „hot-warm” z trzema „gorącymi” węzłami zlokalizowanymi w różnych szafach w centrum danych. Przekierowaliśmy do nich logi za pomocą maski, której w żadnym wypadku nie należy zgubić - nginx, a także logi błędów aplikacji. Do pozostałych węzłów przesłano drobne logi - debugowanie, ostrzeżenie itp., a po 24 godzinach przesłane zostały „ważne” logi z „gorących” węzłów.

Aby nie zwiększać liczby małych indeksów, przeszliśmy z rotacji czasu na mechanizm rollover. Na forach pojawiało się wiele informacji, że rotacja po wielkości indeksu jest bardzo zawodna, dlatego postanowiliśmy zastosować rotację po ilości dokumentów w indeksie. Przeanalizowaliśmy każdy indeks i zapisaliśmy liczbę dokumentów, po której rotacja powinna zadziałać. Tym samym osiągnęliśmy optymalny rozmiar sharda - nie więcej niż 50 GB. 

Optymalizacja klastrów

Jak w CIAN ujarzmiliśmy terabajty logów

Nie pozbyliśmy się jednak całkowicie problemów. Niestety nadal pojawiały się małe indeksy: nie osiągnęły określonego wolumenu, nie były rotowane i zostały usunięte poprzez globalne czyszczenie indeksów starszych niż trzy dni, ponieważ usunęliśmy rotację według daty. Doprowadziło to do utraty danych w związku z tym, że indeks z klastra zniknął całkowicie, a próba zapisu do nieistniejącego indeksu złamała logikę kuratora, którego używaliśmy do zarządzania. Alias ​​do zapisu został przekształcony w indeks i złamał logikę rollover, powodując niekontrolowany wzrost niektórych indeksów aż do 600 GB. 

Na przykład dla konfiguracji rotacji:

сurator-elk-rollover.yaml

---
actions:
  1:
    action: rollover
    options:
      name: "nginx_write"
      conditions:
        max_docs: 100000000
  2:
    action: rollover
    options:
      name: "python_error_write"
      conditions:
        max_docs: 10000000

Jeśli nie było aliasu przejścia, wystąpił błąd:

ERROR     alias "nginx_write" not found.
ERROR     Failed to complete action: rollover.  <type 'exceptions.ValueError'>: Unable to perform index rollover with alias "nginx_write".

Rozwiązanie tego problemu zostawiliśmy na następną iterację i zajęliśmy się innym zagadnieniem: przeszliśmy na logikę ściągania Logstasha, która przetwarza przychodzące logi (usuwając niepotrzebne informacje i wzbogacając). Umieściliśmy go w oknie dokowanym, które uruchamiamy za pomocą docker-compose, a także umieściliśmy tam logstash-exporter, który wysyła metryki do Prometheusa w celu operacyjnego monitorowania strumienia logów. W ten sposób daliśmy sobie możliwość płynnej zmiany liczby instancji logstash odpowiedzialnych za przetwarzanie każdego typu logu.

Podczas gdy udoskonalaliśmy klaster, ruch na cian.ru wzrósł do 12,8 miliona unikalnych użytkowników miesięcznie. W efekcie okazało się, że nasze przekształcenia trochę opóźniły zmiany w produkcji i stanęliśmy przed faktem, że „ciepłe” węzły nie radziły sobie z obciążeniem i spowalniały całą dostawę kłód. „Gorące” dane otrzymaliśmy bez awarii, jednak musieliśmy interweniować w dostarczenie reszty i wykonać ręczny rollover, aby równomiernie rozłożyć indeksy. 

Jednocześnie skalowanie i zmianę ustawień instancji logstash w klastrze komplikuje fakt, że był to lokalny docker-compose, a wszystkie akcje odbywały się ręcznie (aby dodać nowe końcówki, konieczne było ręczne przejście przez wszystkie serwery i wszędzie wykonaj polecenie docker-compose up -d).

Redystrybucja dziennika

We wrześniu tego roku nadal rozcinaliśmy monolit, obciążenie klastra rosło, a przepływ logów zbliżał się do 30 tys. wiadomości na sekundę. 

Jak w CIAN ujarzmiliśmy terabajty logów

Następną iterację rozpoczęliśmy od aktualizacji sprzętu. Zmieniliśmy pięciu koordynatorów na trzech, wymieniliśmy węzły danych i wygraliśmy pod względem pieniędzy i przestrzeni dyskowej. W przypadku węzłów stosujemy dwie konfiguracje: 

  • Dla węzłów „gorących”: E3-1270 v6 / 960 Gb SSD / 32 Gb x 3 x 2 (3 dla Hot1 i 3 dla Hot2).
  • Dla „ciepłych” węzłów: E3-1230 v6 / 4Tb SSD / 32 Gb x 4.

W tej iteracji przenieśliśmy indeks z logami dostępu mikroserwisów, który zajmuje tyle samo miejsca co logi front-line nginx, do drugiej grupy trzech „gorących” węzłów. Teraz przechowujemy dane na „gorących” węzłach przez 20 godzin, a następnie przesyłamy je do „ciepłych” węzłów do pozostałych logów. 

Rozwiązaliśmy problem znikania małych indeksów poprzez rekonfigurację ich rotacji. Teraz indeksy są obracane co 23 godziny w każdym razie, nawet jeśli jest tam niewiele danych. Zwiększyło to nieznacznie liczbę shardów (było ich około 800), ale z punktu widzenia wydajności klastra jest to do zaakceptowania. 

W rezultacie w klastrze było sześć „gorących” i tylko cztery „ciepłe” węzłów. Powoduje to niewielkie opóźnienie w żądaniach w długich odstępach czasu, ale zwiększenie liczby węzłów w przyszłości rozwiąże ten problem.

W tej iteracji rozwiązano również problem braku półautomatycznego skalowania. W tym celu wdrożyliśmy klaster infrastrukturalny Nomad – podobny do tego, który wdrożyliśmy już w środowisku produkcyjnym. Na razie ilość Logstasha nie zmienia się automatycznie w zależności od obciążenia, ale do tego dojdziemy.

Jak w CIAN ujarzmiliśmy terabajty logów

Plany na przyszłość

Wdrożona konfiguracja doskonale się skaluje i obecnie przechowujemy 13,3 TB danych – wszystkie logi przez 4 dni, co jest niezbędne do awaryjnej analizy alertów. Część logów konwertujemy na metryki, które dodajemy do Graphite. Aby ułatwić pracę inżynierom, posiadamy metryki dla klastra infrastruktury oraz skrypty do półautomatycznej naprawy typowych problemów. Po zwiększeniu liczby węzłów danych, co jest zaplanowane na przyszły rok, przejdziemy na przechowywanie danych z 4 do 7 dni. To wystarczy do pracy operacyjnej, ponieważ zawsze staramy się badać incydenty tak szybko, jak to możliwe, a do dochodzeń długoterminowych dostępne są dane telemetryczne. 

W październiku 2019 ruch na cian.ru wzrósł już do 15,3 mln unikalnych użytkowników miesięcznie. Stało się to poważnym testem rozwiązania architektonicznego dostarczania kłód. 

Teraz przygotowujemy się do aktualizacji ElasticSearch do wersji 7. Jednak w tym celu będziemy musieli zaktualizować mapowanie wielu indeksów w ElasticSearch, ponieważ zostały one przeniesione z wersji 5.5 i zostały uznane za przestarzałe w wersji 6 (po prostu nie istnieją w wersji 7). Oznacza to, że podczas procesu aktualizacji na pewno wystąpi siła wyższa, która pozostawi nas bez logów do czasu rozwiązania problemu. Z wersji 7 najbardziej nie możemy się doczekać Kibany z ulepszonym interfejsem i nowymi filtrami. 

Osiągnęliśmy nasz główny cel: przestaliśmy tracić logi i skróciliśmy czas przestoju klastra infrastruktury z 2-3 awarii tygodniowo do kilku godzin prac konserwacyjnych miesięcznie. Cała ta praca w produkcji jest prawie niewidoczna. Jednak teraz możemy dokładnie określić co się dzieje z naszym serwisem, możemy to szybko zrobić w trybie cichym i nie martwić się, że logi zostaną utracone. Ogólnie jesteśmy zadowoleni, szczęśliwi i przygotowujemy się na nowe wyczyny, o których porozmawiamy później.

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

Dodaj komentarz