Przechowywanie metryk: jak przeszliśmy z Graphite+Whisper na Graphite+ClickHouse

Cześć wszystkim! W swoim W poprzednim artykule Pisałem o organizacji modułowego systemu monitorowania dla architektury mikroserwisów. Nic nie stoi w miejscu, nasz projekt nieustannie rośnie, a liczba przechowywanych metryk również. Jak zorganizowaliśmy przejście z Graphite+Whisper na Graphite+ClickHouse w warunkach wysokich obciążeń, o oczekiwaniach wobec niego i wynikach migracji przeczytacie poniżej.

Przechowywanie metryk: jak przeszliśmy z Graphite+Whisper na Graphite+ClickHouse

Zanim opowiem, jak zorganizowaliśmy przejście z przechowywania metryk w Graphite+Whisper na Graphite+ClickHouse, chciałbym podać informacje o przyczynach podjęcia takiej decyzji oraz o wadach Whisper, z którymi żyliśmy przez długi czas.

Problemy Graphite+Whisper

1. Wysokie obciążenie systemu dyskowego

W momencie przejścia otrzymywaliśmy około 1,5 mln metryk na minutę. Przy takim strumieniu wykorzystanie dysków na serwerach wynosiło ~30%. Ogólnie to było całkiem akceptowalne — wszystko działało stabilnie, dane były szybko zapisywane i szybko odczytywane… Do momentu, gdy jedna z drużyn deweloperskich nie wprowadziła nowej funkcji i nie zaczęła nam przesyłać 10 mln metryk na minutę. Wtedy system dyskowy był mocno obciążony i zauważyliśmy 100% wykorzystania. Problem udało się szybko rozwiązać, ale pozostał niesmak.

2. Brak replikacji i spójności

Najprawdopodobniej tak jak wszyscy, którzy używają/używali Graphite+Whisper, wysyłaliśmy ten sam strumień metryk jednocześnie na kilka serwerów Graphite w celu zapewnienia odporności na awarie. I nie było z tym dużych problemów — do momentu, gdy jeden z serwerów z jakiegoś powodu nie padł. Czasami udawało nam się szybko przywrócić padły serwer, a carbon-c-relay zdążał zalać go metrykami z pamięci podręcznej, a czasami nie. I wtedy w metrykach powstawała luka, którą zasypywaliśmy za pomocą rsynca. Procedura była dość długa. Ratujące było tylko to, że coś takiego zdarzało się bardzo rzadko. Okresowo także wybieraliśmy losowy zestaw metryk i porównywaliśmy je z innymi takimi samymi na sąsiednich węzłach klastra. W około 5% przypadków kilka wartości różniło się, co nas nieco niepokoiło.

3. Duża ilość zajmowanego miejsca

Ponieważ w Graphite zapisujemy nie tylko metryki infrastrukturalne, ale także metryki biznesowe (a teraz także metryki z Kubernetes), dość często mamy sytuację, w której w metryce znajduje się tylko kilka wartości, a plik .wsp jest tworzony z uwzględnieniem całego okresu retencji i zajmuje przydzieloną objętość miejsca, która wynosiła około 2 MB. Problem pogłębia się tym, że takich plików z czasem pojawia się bardzo wiele, a podczas tworzenia raportów o nich na odczytywanie pustych punktów poświęca się dużo czasu i zasobów.

Od razu warto zauważyć, że z problemami opisanymi powyżej można walczyć różnymi metodami i z różnym stopniem efektywności, ale im więcej danych zaczyna do Ciebie napływać, tym bardziej się one zaostrzają.

Mając wszystko, co wymienione powyżej (z uwzględnieniem poprzedniej artykułu), a także stały wzrost liczby otrzymywanych metryk oraz chęć przekształcenia wszystkich metryk na interwał przechowywania wynoszący 30 sek. (w razie potrzeby — do 10 sek.), zdecydowaliśmy się spróbować Graphite+ClickHouse jako perspektywicznej alternatywy dla Whisper.

Graphite+ClickHouse. Oczekiwania

Odwiedzając kilka meetupów organizowanych przez ludzi z Yandexa, czytając parę artykułów na Habrze, przeszukując dokumentację i znajdując sensowne komponenty do integrowania ClickHouse z Graphite, postanowiliśmy działać!

Chcieliśmy osiągnąć następujące cele:

  • zmniejszyć wykorzystanie systemu dyskowego z 30% do 5%;
  • zmniejszyć zajmowaną przestrzeń z 1 TB do 100 GB;
  • mieć możliwość przyjmowania 100 milionów metryk na minutę na serwer;
  • replikację danych i odporność na awarie z pudełka;
  • nie siedzieć nad tym projektem przez rok i zrealizować przejście w rozsądnym czasie;
  • przełączyć się bez przestojów.

Dosyć ambitnie, prawda?

Graphite+ClickHouse. Komponenty

Do uzyskiwania danych za pomocą protokołu Graphite i późniejszego zapisywania ich w ClickHouse wybrano carbon-clickhouse (golang).

Jako bazę danych do przechowywania szeregów czasowych wybrano najnowszą w tamtym czasie stabilną wersję ClickHouse 1.1.54253. Podczas pracy z nim pojawiły się problemy: w logach pojawiało się mnóstwo błędów, a nie było do końca jasne, co z nimi zrobić. W dyskusji z Romanem Lomonosowem (autorem carbon-clickhouse, graphite-clickhouse i jeszcze wielu innych rzeczy) wybrano starszą wersję 1.1.54236.Błędy zniknęły — wszystko zaczęło działać jak należy.

Do odczytu danych z ClickHouse wybrano graphite-slickhouse (golang). Jako interfejs API dla Graphite — carbonapi (golang). Aby zorganizować replikację między tabelami ClickHouse, użyto zookeeper. Do routingu metryk pozostawiliśmy naszą ulubioną carbon-c-relay (C) (patrz wcześniejszy artykuł).

Graphite+ClickHouse. Struktura tabel

„graphite” — baza danych stworzona przez nas dla tabel monitorujących.

„graphite.metrics” — tabela z silnikiem ReplicatedReplacingMergeTree (replikowana ReplacingMergeTree). W tej tabeli przechowywane są nazwy metryk i ścieżki do nich.

CREATE TABLE graphite.metrics ( Date Date, Level UInt32, Path String, Deleted UInt8, Version UInt32 ) ENGINE = ReplicatedReplacingMergeTree('\/clickhouse\/tables\/replicator\/graphite.metrics', 'r1', Date, (Level, Path), 8192, Version);

„graphite.data” — tabela z silnikiem ReplicatedGraphiteMergeTree (replikowana GraphiteMergeTree). W tej tabeli przechowywane są wartości metryk.

CREATE TABLE graphite.data ( Path String, Value Float64, Time UInt32, Date Date, Timestamp UInt32 ) ENGINE = ReplicatedGraphiteMergeTree('\/clickhouse\/tables\/replicator\/graphite.data', 'r1', Date, (Path, Time), 8192, 'graphite_rollup')

„graphite.date_metrics” — tabela wypełniana na podstawie warunków, z silnikiem ReplicatedReplacingMergeTree. Do tej tabeli zapisywane są nazwy wszystkich metryk, które wystąpiły w ciągu dnia. Powody stworzenia opisano w sekcji „Problemy” na końcu tego artykułu.

CREATE MATERIALIZED VIEW graphite.date_metrics ( Path String, Level UInt32, Date Date) ENGINE = ReplicatedReplacingMergeTree('\/clickhouse\/tables\/replicator\/graphite.date_metrics', 'r1', Date, (Level, Path, Date), 8192) AS SELECT toUInt32(length(splitByChar('.', Path))) AS Level, Date, Path FROM graphite.data

„graphite.data_stat” — tabela wypełniana na podstawie warunków, z silnikiem ReplicatedAggregatingMergeTree (replikowana AggregatingMergeTree). Do tej tabeli zapisywane jest liczba przychodzących metryk, z podziałem na 4 poziomy zagnieżdżenia.

CREATE MATERIALIZED VIEW graphite.data_stat ( Date Date, Prefix String, Timestamp UInt32, Count AggregateFunction(count)) ENGINE = ReplicatedAggregatingMergeTree('\/clickhouse\/tables\/replicator\/graphite.data_stat', 'r1', Date, (Timestamp, Prefix), 8192) AS SELECT toStartOfMonth(now()) AS Date, replaceRegexpOne(Path, '^([^.]+.[^.]+.[^.]+).*$', '1') AS Prefix, toUInt32(toStartOfMinute(toDateTime(Timestamp))) AS Timestamp, countState() AS Count FROM graphite.data GROUP BY Timestamp, Prefix

Graphite+ClickHouse. Schemat interakcji komponentów

Przechowywanie metryk: jak przeszliśmy z Graphite+Whisper na Graphite+ClickHouse

Graphite+ClickHouse. Migracja danych

Jak pamiętamy z oczekiwań wobec tego projektu, przejście na ClickHouse powinno odbyć się bez przestojów, w związku z czym musieliśmy w jakiś sposób przełączyć nasz cały system monitorowania na nowe magazyn w sposób maksymalnie przejrzysty dla naszych użytkowników.
Zrobiliśmy to w ten sposób.

  • W carbon-c-relay dodaliśmy regułę wysyłania dodatkowego strumienia metryk do carbon-clickhouse na jednym z serwerów biorących udział w replikacji tabel ClickHouse.

  • Napisaliśmy mały skrypt w Pythonie, który za pomocą biblioteki whisper-dump odczytywał wszystkie pliki .wsp z naszego repozytorium i przesyłał te dane do opisanego wcześniej carbon-clickhouse w 24 wątkach. Liczba przyjmowanych wartości metryk w carbon-clickhouse osiągnęła 125 mln/min, a ClickHouse nawet się nie spocił.

  • Stworzyliśmy oddzielny DataSource w Grafanie w celu debugowania funkcji używanych w istniejących dashboardach. Zidentyfikowaliśmy listę funkcji, które wykorzystywaliśmy, ale nie były one zaimplementowane w carbonapi. Dopisaliśmy te funkcje i wysłaliśmy PR-y do autorów carbonapi (szczególne podziękowania dla nich).

  • Aby przełączyć obciążenie odczytu, zmieniliśmy punkty końcowe w ustawieniach load balancerów z graphite-api (interfejs API dla Graphite+Whisper) na carbonapi.

Graphite+ClickHouse. Wyniki

  • ograniczyliśmy wykorzystanie systemu dyskowego z 30% do 1%;

    Przechowywanie metryk: jak przeszliśmy z Graphite+Whisper na Graphite+ClickHouse

  • zmniejszyliśmy zajmowaną przestrzeń z 1 TB do 300 GB;
  • mamy możliwość przyjmowania 125 mln metryk na minutę na serwer (szczyty w momencie migracji);
  • przenieśliśmy wszystkie metryki na 30-sekundowy interwał przechowywania;
  • uzyskaliśmy replikację danych i odporność na awarie;
  • przełączyliśmy się bez przestojów;
  • wszystko zajęło nam około 7 tygodni.

Graphite+ClickHouse. Problemy

W naszym przypadku nie obyło się bez niespodzianek. Oto co napotkaliśmy po przejściu.

  1. ClickHouse nie zawsze na bieżąco odczytuje konfiguracje, czasami trzeba go ponownie uruchomić. Na przykład, w przypadku opisu klastra zookeeper w konfiguracji ClickHouse — nie był on stosowany do momentu ponownego uruchomienia clickhouse-server.
  2. Nie przeszły duże zapytania ClickHouse, dlatego nasza linia połączenia w graphite-clickhouse wygląda tak:
    url = "http://localhost:8123/?max_query_size=268435456&max_ast_elements=1000000"
  3. W ClickHouse dość często wydawane są nowe wersje stabilnych wydań, mogą się tam pojawić niespodzianki: bądź ostrożny.
  4. Dynamicznie tworzone kontenery w Kubernetes wysyłają dużą ilość metryk z krótkim i losowym okresem życia. Punktów dla takich metryk jest niewiele, a problemy z miejscem nie występują. Jednak podczas budowania zapytań ClickHouse pobiera ogromną ilość tych metryk z tabeli ‘metrics’. W 90% przypadków dane dotyczące nich są niedostępne na przestrzeni okna (24 godziny). Czas poświęcany na wyszukiwanie tych danych w tabeli ‘data’ jest znaczący i ostatecznie prowadzi do timeoutu. Aby rozwiązać ten problem, zaczęliśmy prowadzić osobny widok z informacjami o metrykach, które pojawiły się w ciągu ostatnich 24 godzin. W ten sposób, przy tworzeniu raportów (wykresów) dotyczących dynamicznie tworzonych kontenerów, pytamy tylko o te metryki, które pojawiły się w określonym oknie czasowym, a nie przez cały czas, co znacząco przyspieszyło tworzenie raportów na ich temat. Dla powyższego rozwiązania stworzono graphite-clickhouse (fork), obejmujący implementację pracy z tabelą date_metrics.

Graphite+ClickHouse. Tagi

Od wersji 1.1.0 Graphite oficjalnie wsparcie dla tagów. I aktywnie myślimy o tym, co i jak należy zrobić, aby wspierać tę inicjatywę w stosie graphite+clickhouse.

Graphite+ClickHouse. Wykrywacz anomalii

Na podstawie opisanej powyżej infrastruktury zrealizowaliśmy prototyp wykrywacza anomalii i działa! Ale więcej na ten temat — w następnym artykule.

Subskrybuj, kliknij strzałkę w górę i bądź szczęśliwy!

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster