Graphitgraphite-logoe ist tot. So zumindest ist die Meinung vieler auf Twitter und Co. Ein ganz anderes Bild zeigt sich allerdings in den Github Repositories. In kurzen Zeitabständen wird von mehreren Entwicklern commited. Bugs werden gefixt und Features implementiert. Die Geschwindigkeit, in der es Releases gibt, könnte natürlich schneller sein. Software wird aber nicht automatisch besser durch hohe Versionsnummern, das haben andere schon oft bewiesen. Das Projekt ist also alles andere als tot. Ganz im Gegenteil, sogar ein schönes neues Logo gibt es.
Was unser Interesse geweckt hat
Doch was ist es, das Graphite so interessant für viele Devs und Ops macht? Die I/O die es auf den Festplatten verursacht ist es mit Sicherheit nicht. Auch das verwalten dieser Whisper Dateien, samt Storage Schema und Aggregation Methods bereitet vermutlich den wenigsten von uns Spaß. Graphite hat etwas gebracht, was kein anderer auf diese Art und Weise hatte: eine API auf Metriken. Nicht nur das, sogar Funktionen zum Gruppieren, Transformieren und Filtern sind enthalten. Plötzlich ist es so einfach, Datenpunkte darzustellen und Graphen in eigene Tools einzubauen. Dem Kollegen mal eben einen maßgefertigten Graphen schicken? Kein Problem. Was bei RRD noch zu Kopfschütteln und knirschenden Zähnen, noch schlimmer: zu Perl Skripten geführt hat, ist nun ganz einfach und selbstverständlich. Graphite hat die Art und Weise wie wir mit Graphen umgehen verändert. Und das ist auch gut so.
Wichtig beim Thema Skalierung: SSDs
Das Thema der Skalierung ist und bleibt dennoch eine Herausforderung. Weil es eben so einfach zu verwenden ist, landen mit der Zeit mehr und mehr Daten in der Datengrube. Das System muss mitwachsen, andernfalls besteht die Gefahr, Daten zu verlieren. Es werden viele kleine Datensätze in kurzen Zeitabständen geschrieben. Am besten kann das natürlich mit SSDs abgefangen werden. Wem SSDs für das Gesamtsetup zu teuer sind, der kann sich mit Facebooks Flashcache einen Cache basteln und die permanente Lagerung auf mechanische Platten verschieben.
Die Geschichte eines Datenpunkts
So ein Datenpunkt beginnt seine Reise in der Regel auf einem Server. Dort wird er aufgesammelt von einem Collector, beispielsweise CollectD, Icinga2 oder Diamond. In voller Geschwindigkeit geht es dann Richtung Graphite. Sofern das Setup nicht minimal gehalten wurde, wartet dort eine ganze Kette an Carbon Daemons, angeführt vom Carbon Relay. Diese erste Aufprallstelle nimmt alle Metriken entgegen und verwaltet sie in Queues. Jedes nachgelagerte Ziel (Aggregator oder Cache) bekommt seine eigene. Wie voll diese Queue ist, hängt davon ab, wie schnell die Anschlussstelle (Aggregator oder Cache) die Metriken abarbeiten kann. Läuft diese Queue voll, werden Datenpunkte verworfen. Genau so verhält sich auch der Carbon Aggregator. Die Standardeinstellung MAX_QUEUE_SIZE sollte also regelmäßig überprüft werden.
graphite-queues-and-caches
Carbon Cache als zentrale Stelle
Sehr ähnlich verhält sich Carbon Cache. Er erstellt für jeden Metrikpfad eine eigene Queue. In jeder dieser Queues werden die dazugehörigen Datenpunkte gesammelt, so können später in einer einzigen Schreiboperation mehrere Datenpunkte auf ein Mal geschrieben werden. Das spart I/O, die Daten liegen aber so lange im RAM. Mit der Einstellung CACHE_WRITE_STRATEGY kann eine Strategie ausgewählt werden, mit der Daten geschrieben werden. Ein “Writer Thread” arbeitet diese Queues ab und schreibt die Datenpunkte in die entsprechenden Whisper Dateien. Diese einzelnen Queues können zwar prinzipiell erst mal nicht volllaufen, der gesamte Cache kann es aber. Mit der Option MAX_CACHE_SIZE wird eine Größe festgelegt, die für die Gesamtheit aller Metrik-Queues gilt.
Am besten erzählt der die Geschichte, der sie erlebt hat
Diese Geschichte eines Datenpunkts wird von den Carbon Daemons selbst erzählt. Natürlich in Bildern, mit Graphen. Alle diese Daemons speichern Messwerte über sich selbst. Anhand dieser lässt sich genau verfolgen, wie sich das Setup verhält. Die wichtigsten Metriken dabei sind:

  • Relay
    • metricsReceived – Anzahl der empfangenen Metriken
    • sent – Anzahl der weitergeleiteten Metriken, aufgeschlüsselt pro Ziel
    • relayMaxQueueLength – Aktuelle größe der Queue
    • fullQueueDrops – verworfene Metriken, aufgrund von vollen Queues
  • Aggregator
    • metricsReceived – empfangene Metriken, sollte mit der Anzahl gesendeter Metriken vom Relay übereinstimmen
  • Cache
    • cache.queues – Anzahl der Metrik-Queues
    • cache.size – Summe aller Datenpunkte in allen Metrik-Queues
    • pointsPerUpdate – Anzahl der Datenpunkte die pro Schreiboperation geschrieben werden
    • avgUpdateTime – So lange dauert eine Schreiboperation im Durchschnitt

Das sind natürlich nicht alle, Geschichten brauchen schließlich viel mehr Details. Alle drei Daemons liefern auch Daten über die Ausnutzung von CPU, Speicher und viele weitere Messwerte.
So endet die Reise des Datenpunkts in seinem letzten Ziel: der Whisper Datei. Dort wird er wieder und wieder abgefragt, zu Zwecken der Darstellung. Bis seine Zeit abgelaufen ist und er überschrieben wird, damit endet die Reise dann endgültig.

Blerim Sheqa
Blerim Sheqa
Product Manager

Blerim ist seit 2013 bei NETWAYS und seitdem schon viel in der Firma rum gekommen. Neben dem Support und diversen internen Projekten hat er auch im Team Infrastruktur tatkräftig mitgewirkt. Hin und wieder lässt er sich auch den ein oder anderen Consulting Termin nicht entgehen. Mittlerweile kümmert sich Blerim hauptsächlich im Icinga Umfeld um die technischen Partner und deren Integrationen in Verbindung mit Icinga 2.