
Gruß habr.
Wenn jemand ein Graphite-Web-System betreibt und mit einem Flüsterspeicherleistungsproblem (E / A, Speicherplatzverbrauch) konfrontiert ist, sollte sich die Chance, dass ClickHouse als Ersatz verwendet wird, auf eins richten. Diese Aussage impliziert, dass eine Implementierung eines Drittanbieters, wie Carbonwriter oder Go-Carbon, bereits als Empfangsmetrik des Daemons verwendet wird.
ClickHouse löst die beschriebenen Probleme gut. Nach der Übertragung von 2TiB-Daten aus Whisper passen sie beispielsweise in 300GiB. Ich werde nicht im Detail auf den Vergleich eingehen, es gibt genug Artikel zu diesem Thema. Außerdem war bis vor kurzem mit unserem ClickHouse-Speicher alles perfekt.
Verbrauchsprobleme
Auf den ersten Blick sollte alles gut funktionieren. Im Anschluss an die Dokumentation erstellen wir eine Konfiguration für das Metrik-Speicherschema (im Folgenden retention
) und erstellen dann eine Tabelle gemäß der Empfehlung des ausgewählten Backends für Graphite-Web: Carbon-Clickhouse + Graphite-Clickhouse oder Graphouse , je nachdem, welcher Stack verwendet wird. Und ... die Zeitbombe geht an.
Um zu verstehen, welche, müssen Sie wissen, wie die Einfügungen und der weitere Lebensweg der Daten in den Tabellen der * MergeTree ClickHouse-Motorenfamilie (Diagramme aus der Präsentation von Alexei Zatelepin) sind:
- Ein
eingefügt. In unserem Fall sind Metriken angekommen.

- Jeder dieser Blöcke wird vor dem Schreiben auf die Festplatte nach dem
ORDER BY
Schlüssel sortiert, der beim Erstellen der Tabelle angegeben wurde. - Nach dem Sortieren wird ein Datenelement auf die Festplatte geschrieben.

- Der Server überwacht im Hintergrund, dass es nicht viele solcher Teile gibt, und startet
merge
im Hintergrund ( merge
, im Folgenden Merge).


- Der Server stoppt die Ausführung von Merges, sobald die Daten nicht mehr aktiv
partition
OPTIMIZE
. Sie können den Vorgang jedoch manuell mit dem Befehl OPTIMIZE
. - Befindet sich nur noch ein Teil in der Partition, können Sie die Zusammenführung nicht mit dem üblichen Befehl starten,
OPTIMIZE ... FINAL
müssen OPTIMIZE ... FINAL
So kommen die ersten Metriken an. Und sie nehmen einen bestimmten Raum ein. Nachfolgende Ereignisse können in Abhängigkeit von vielen Faktoren leicht variieren:
- Der Partitionierungsschlüssel kann entweder sehr klein (Tag) oder sehr groß (mehrere Monate) sein.
- Die Aufbewahrungskonfiguration kann mehrere signifikante Schwellenwerte für die Datenaggregation in der aktiven Partition (in die der Metrikdatensatz verschoben wird) berücksichtigen oder nicht.
- Wenn es viele Daten gibt, können sich die frühesten Teile, die aufgrund von Zusammenführungen im Hintergrund bereits riesig sein können (bei Auswahl eines suboptimalen Partitionsschlüssels), nicht mit neuen kleinen Teilen abfinden.
Und alles endet immer gleich. Der Platz, den Metriken in ClickHouse einnehmen, wächst nur, wenn:
OPTIMIZE ... FINAL
manuell oder manuell an- Fügen Sie nicht fortlaufend Daten in alle Partitionen ein, um früher oder später eine Zusammenführung im Hintergrund zu starten
Die zweite Methode scheint am einfachsten zu implementieren zu sein und deshalb ist er falsch und wurde zuerst getestet.
Ich habe ein ziemlich einfaches Python-Skript geschrieben, das für jeden Tag in den letzten 4 Jahren Dummy-Metriken gesendet hat und das stündlich von der Krone ausgeführt wird.
Da die gesamte Arbeit von ClickHouse DBMS auf der Tatsache basiert, dass dieses System früher oder später die gesamte Hintergrundarbeit erledigt, aber nicht bekannt ist, wann, konnte ich nicht warten, bis sich die riesigen alten Teile mit den neuen kleinen zusammenfinden. Es wurde klar, dass wir nach einer Möglichkeit suchen mussten, erzwungene Optimierungen zu automatisieren.

Sehen Sie sich die Struktur der Tabelle system.parts an . Dies sind umfassende Informationen zu allen Tabellen auf dem ClickHouse-Server. Es enthält unter anderem folgende Spalten:
- DB Name (
database
); - Tabellenname (
table
); - Partitionsname und ID (
partition
& partition_id
ID); - wann das Stück erstellt wurde (
modification_time
); - minimales und maximales Datum in einem Stück (Aufteilung erfolgt nach Tag) (
min_date
& max_date
);
Es gibt auch eine system.graphite_retentions- Tabelle mit den folgenden interessanten Feldern:
- DB-Name (
Tables.database
); - Tabellenname (
Tables.table
); - das Alter der Metrik, ab dem die nächste Aggregation (
age
) angewendet werden soll;
Also:
- Wir haben eine Stückliste und eine Tabelle mit Aggregationsregeln.
- Kombinieren Sie ihre Schnittmenge und erhalten Sie alle * GraphiteMergeTree-Tabellen.
- Wir suchen alle Trennwände, in denen:
- mehr als ein Stück
- oder es ist an der Zeit, die folgende Aggregationsregel anzuwenden, und
modification_time
älter als dieser Moment.
Implementierung
Diese Anfrage SELECT concat(p.database, '.', p.table) AS table, p.partition_id AS partition_id, p.partition AS partition,
Gibt alle Partitionen von * GraphiteMergeTree-Tabellen zurück, deren Zusammenführung Speicherplatz freigeben soll. Alles, was übrig bleibt, ist das Kleine: Gehen Sie alle mit der OPTIMIZE ... FINAL
. Bei der endgültigen Implementierung wurde auch berücksichtigt, dass Partitionen mit einem aktiven Datensatz nicht berührt werden müssen.
Genau das leistet das Graphite-Ch-Optimizer- Projekt. Ehemalige Kollegen von Yandex.Market testeten es im Produkt, das Ergebnis der Arbeit ist unten zu sehen.

Wenn Sie das Programm mit ClickHouse auf dem Server ausführen, wird es nur im Dämonmodus ausgeführt. Einmal pro Stunde wird eine Anforderung ausgeführt, in der überprüft wird, ob neue Partitionen, die älter als drei Tage sind, optimiert werden können.
In naher Zukunft - zumindest deb Pakete und wenn möglich - auch rpm.
UPD: Pakete sind für Github-Releases verfügbar, und Arbeitsimages finden Sie im Docker-Hub im Repository von innogames / graphite-ch-optimizer.
Anstelle einer Schlussfolgerung
In den letzten über neun Monaten habe ich viel Zeit in meinem InnoGames- Unternehmen verbracht, an der Schnittstelle zwischen ClickHouse und Graphite-Web. Es war eine gute Erfahrung, die es ermöglichte, schnell von Whisper zu ClickHouse als Speicher für Metriken zu wechseln. Ich hoffe, dass dieser Artikel so etwas wie der Beginn eines Zyklus darüber ist, welche Verbesserungen wir an verschiedenen Teilen dieses Stacks vorgenommen haben und was in Zukunft getan wird.
Gemeinsam mit v0devil wurden auf Wunsch mehrere Liter Bier und Admin-Tage entwickelt , wofür ich ihm meinen Dank aussprechen möchte. Und auch für die Überprüfung dieses Artikels.
Projektseite auf Github