Heute arbeiten auf unserem Projekt, neben monolithischem Code, zahlreiche Mikrodienste. Jeder von ihnen benötigt umfassende Überwachung. Dies in solch einem Umfang mit DevOps-Ingenieuren zu erledigen, ist problematisch. Deshalb haben wir ein Überwachungssystem entwickelt, das als Service für Entwickler fungiert. Sie können eigenständig Metriken in das Überwachungssystem einpflegen, diese nutzen, Dashboards erstellen und Alarme einstellen, die bei Erreichen bestimmter Grenzwerte ausgelöst werden. Die DevOps-Ingenieure sind lediglich für die Infrastruktur und Dokumentation zuständig.
Dieser Beitrag ist eine Aufzeichnung meines Vortrags aus unserer auf der RIT++. Viele hatten gebeten, die schriftlichen Versionen der Vorträge dort zu erstellen. Wenn Sie auf der Konferenz waren oder das Video angesehen haben, werden Sie nichts Neues finden. Allen anderen – willkommen unter dem Artikel. Ich werde erzählen, wie wir zu diesem System gekommen sind, wie es funktioniert und wie wir planen, es zu aktualisieren.

Die Vergangenheit: Pläne und Entwürfe
Wie sind wir zum bestehenden Überwachungssystem gekommen? Um diese Frage zu beantworten, müssen wir ins Jahr 2015 zurückblicken. So sah es damals aus:

Wir hatten etwa 24 Knotenpunkte, die für das Monitoring zuständig waren. Hier gibt es eine ganze Reihe verschiedener Cron-Jobs, Skripte und Dienste, die in irgendeiner Weise überwachen, Nachrichten senden und Funktionen ausführen. Wir haben festgestellt, dass eine solche Systemstruktur mit der Zeit weniger tragfähig sein wird. Es macht keinen Sinn, diese weiterzuentwickeln: sie ist einfach zu umständlich.
Wir haben uns entschlossen, die Monitoring-Elemente auszuwählen, die wir beibehalten und weiterentwickeln möchten, und solche, von denen wir uns trennen werden. Am Ende blieben 19 übrig. Es sind nur noch Graphite, Aggregatoren und Grafana als Dashboard übrig. Aber wie wird das neue System aussehen? So:

Wir haben ein Metrics-Repository: das sind Graphite, die auf schnellen SSDs basieren, und bestimmte Aggregatoren für Metriken. Darüber hinaus verwenden wir Grafana zur Darstellung von Dashboards und Moira für das Alerting. Außerdem möchten wir ein System zur Anomalieerkennung entwickeln.
Standard: Monitoring 2.0
So sahen die Pläne im Jahr 2015 aus. Aber wir mussten nicht nur die Infrastruktur und den Dienst selbst vorbereiten, sondern auch die dazugehörige Dokumentation. Für uns haben wir einen Unternehmensstandard entwickelt, den wir Monitoring 2.0 genannt haben. Welche Anforderungen gab es an das System?
- ständige Verfügbarkeit;
- Intervall der Metrikspeicherung = 10 Sekunden;
- strukturierte Speicherung von Metriken und Dashboards;
- SLA > 99,99%
- Erfassung von Ereignismetriken über UDP (!).
Wir benötigten UDP, da wir einen hohen Datenverkehr und viele Ereignisse haben, die Metriken generieren. Wenn wir alle gleichzeitig in Graphite schreiben, würde das Speichersystem zusammenbrechen. Außerdem wählten wir Top-Level-Präfixe für alle Metriken.

Jedes dieser Präfixe hat eine spezifische Eigenschaft. Es gibt Metriken zu Servern, Netzwerken, Containern, Ressourcen, Anwendungen und so weiter. Es gibt eine klare, strenge, typisierte Filterung, bei der wir nur die Metriken der ersten Ebene akzeptieren und die anderen einfach verwerfen. So haben wir dieses System 2015 geplant. Und wie sieht es jetzt aus?
Aktuell: Schema der Interaktion zwischen den Überwachungskomponenten
Zunächst überwachen wir die Applikationen: unseren PHP-Code, Anwendungen und Microservices – kurz gesagt, alles, was unsere Entwickler erstellen. Alle Applikationen senden über UDP Metriken an den Aggregator Brubeck (statsd, in C neu geschrieben). Er hat sich in synthetischen Tests als der schnellste erwiesen. Und er sendet die bereits aggregierten Metriken über TCP an Graphite.
Es gibt einen bestimmten Typ von Metriken, die als Timer bezeichnet werden. Das ist eine sehr nützliche Funktion. Zum Beispiel sendet man für jede Verbindung eines Nutzers zum Dienst eine Metrik an Brubeck mit der Antwortzeit. Es kommen Millionen von Antworten, und der Aggregator liefert nur 10 Metriken. Sie haben die Anzahl der eingegangenen Benutzer, die maximale, minimale und durchschnittliche Antwortzeit, die Median und 4 Perzentile. Anschließend werden die Daten an Graphite übermittelt, und wir sehen sie alle live.
Wir haben auch eine Aggregation für Metriken im Bereich Hardware, Software, Systemmetriken und unser altes Überwachungssystem Munin (das bis 2015 bei uns in Betrieb war). All dies sammeln wir über den C-Dämon CollectD (der eine ganze Reihe von verschiedenen Plugins integriert hat und alle Ressourcen des Hosts abfragen kann, auf dem er installiert ist; Sie müssen nur in der Konfiguration angeben, wo die Daten geschrieben werden sollen) und übertragen die Daten damit nach Graphite. Er unterstützt auch Python-Plugins und Shell-Skripte, sodass Sie Ihre eigenen maßgeschneiderten Lösungen erstellen können: CollectD sammelt diese Daten von einem lokalen oder entfernten Host (nehmen wir an, es gibt Curl) und sendet sie an Graphite.
Alle gesammelten Metriken senden wir an Carbon-c-relay. Dies ist eine von Graphite entwickelte Carbon-Relay-Lösung, die in C optimiert wurde. Es handelt sich um einen Router, der alle Metriken, die wir von unseren Aggregatoren senden, sammelt und an die Knoten weiterleitet. Während der Routing-Phase überprüft er auch die Gültigkeit der Metriken. Erstens müssen sie dem Schema mit den Präfixen entsprechen, das ich zuvor gezeigt habe, und zweitens müssen sie für Graphite gültig sein. Andernfalls werden sie verworfen.
Anschließend sendet Carbon-c-relay die Metriken an den Graphite-Cluster. Wir verwenden Carbon-cache, um die Metriken primär zu speichern, was in Go neu implementiert wurde. Go-Carbon übertrifft aufgrund seiner Multithreading-Fähigkeiten die Leistung von Carbon-cache erheblich. Es nimmt die Daten auf und speichert sie auf Festplatten mithilfe des Whisper-Pakets (Standard, geschrieben in Python). Um die Daten aus unseren Speichern auszulesen, nutzen wir die Graphite API. Diese funktioniert deutlich schneller als das Standard Graphite WEB. Was passiert mit den Daten danach?
Sie laufen in Grafana. Als primäre Datenquelle nutzen wir unsere Graphite-Cluster, und zusätzlich haben wir Grafana als Web-Interface, um Metriken anzuzeigen und Dashboards zu erstellen. Jeder Entwickler hat ein eigenes Dashboard für seinen Service. Danach erstellen sie Grafiken, auf denen die Metriken dargestellt werden, die sie aus ihren Anwendungen senden. Neben Grafana haben wir auch SLAM. Das ist ein Python-Daemon, der SLAs basierend auf Daten aus Graphite berechnet. Wie bereits erwähnt, haben wir mehrere Dutzend Mikrodienste, von denen jeder seine eigenen Anforderungen hat. Mit Hilfe von SLAM greifen wir auf die Dokumentation zu und vergleichen sie mit dem, was in Graphite vorhanden ist, und prüfen, wie gut die Anforderungen mit der Verfügbarkeit unserer Dienste übereinstimmen.
Kommen wir zum Alerting. Dieses ist durch ein robustes System organisiert – Moira. Es ist unabhängig, da es einen eigenen Graphite-Backend hat. Entwickelt von den Jungs von SKB "Kontur", geschrieben in Python und Go, und vollständig Open-Source. Moira erhält den gleichen Datenstrom, der in Graphite fließt. Wenn aus irgendeinem Grund Ihr Speicher ausfällt, funktioniert Ihr Alerting weiter.
Moira wurde in Kubernetes implementiert und verwendet als Hauptdatenbank einen Redis-Servercluster. Dadurch entstand ein ausfallsicheres System. Es vergleicht den Datenstrom mit einer Liste von Triggern: Wenn keine Erwähnung vorhanden ist, wird die Metrik verworfen. So kann es Gigabytes an Metriken pro Minute verarbeiten.
Außerdem haben wir eine Unternehmens-LDAP integriert, mit dem jeder Benutzer des Unternehmenssystems Benachrichtigungen zu bestehenden (oder neu erstellten) Triggern erstellen kann. Da Moira Graphite enthält, unterstützt sie alle Funktionen davon. Deshalb nehmen Sie zunächst eine Zeile und kopieren sie in Grafana. Sehen Sie, wie die Daten in den Diagrammen angezeigt werden. Dann nehmen Sie dieselbe Zeile und kopieren sie in Moira. Sie versehen sie mit Limits und erhalten am Ende ein Alerting. Für all das benötigen Sie keine speziellen Kenntnisse. Moira kann über SMS, E-Mail, Jira, Slack alarmieren... Außerdem unterstützt sie die Ausführung von benutzerdefinierten Skripten. Wenn ein Trigger eintritt und sie auf ein benutzerdefiniertes Skript oder eine Binärdatei abonniert ist, führt sie es aus und übergibt dem Binärprogramm JSON über stdin. Folglich muss Ihr Programm es parsen. Was Sie mit diesem JSON machen – das liegt ganz bei Ihnen. Möchten Sie es in Telegram senden, möchten Sie Aufgaben in Jira erstellen, tun Sie, was immer Sie wollen.
Für das Alerting verwenden wir auch unsere eigene Entwicklung — Imagotag. Wir haben das Dashboard, das normalerweise für elektronische Preisschilder in Geschäften verwendet wird, an unsere Bedürfnisse angepasst. Wir haben Trigger aus Moira integriert, auf denen der aktuelle Zustand und der Zeitpunkt der Ereignisse angezeigt werden. Einige Entwickler haben sich entschieden, auf Benachrichtigungen in Slack und E-Mails zugunsten dieses Dashboards zu verzichten.

Und da wir ein progressives Unternehmen sind, haben wir in diesem System auch Kubernetes überwacht. Wir haben es über Heapster in das System integriert, den wir im Cluster installiert haben. Er sammelt Daten und sendet sie an Graphite. Das Schema sieht folgendermaßen aus:

Überwachungsbestandteile
Hier ist eine Liste der Links zu den Komponenten, die wir für diese Aufgabe verwendet haben. Alle sind Open Source.
Graphite:
- go-carbon:
- whisper:
- graphite-api:
Carbon-c-relay:
Brubeck:
Collectd:
Moira:
Grafana:
Heapster:
Statistik
Und hier sind einige Zahlen zur Funktionsweise unseres Systems.
Aggregator (brubeck)
Anzahl der Metriken: ~ 300.000 / sec
Intervall für den Versand der Metriken an Graphite: 30 sec
Serverressourcennutzung: ~ 6% CPU (bezieht sich auf vollwertige Server); ~ 1 GB RAM; ~ 3 Mbps LAN
Graphit (go-carbon)
Anzahl der Metriken: ~ 1.600.000 / Min
Aktualisierungsintervall der Metriken: 30 Sek.
Metrik-Speicherstruktur: 30 Sek. 35 Tage, 5 Min. 90 Tage, 10 Min. 365 Tage (gibt einen Überblick über den Service über einen längeren Zeitraum)
Serverressourcennutzung: ~ 10% CPU; ~ 20 GB RAM; ~ 30 Mbps LAN
Flexibilität
Bei Avito legen wir großen Wert auf Flexibilität in unserem Monitoring-Service. Warum ist er so gestaltet? Erstens, seine Komponenten sind austauschbar: sowohl die einzelnen Bauteile als auch deren Versionen. Zweitens — Wartbarkeit. Da das gesamte Projekt auf Open-Source basiert, können Sie den Code selbst anpassen, Änderungen vornehmen und Funktionen implementieren, die standardmäßig nicht verfügbar sind. Wir verwenden weit verbreitete Stacks, hauptsächlich Go und Python, was die Umsetzung relativ einfach macht.
Hier ist ein Beispiel für ein tatsächlich aufgetretenes Problem. Eine Metrik in Graphite ist eine Datei. Diese hat einen Namen. Der Dateiname entspricht dem Metriknamen. Und es gibt einen Pfad zu ihr. Die Dateinamen in Linux sind auf 255 Zeichen begrenzt. Und wir haben (als „interne Auftraggeber“) Leute aus der Datenbankabteilung. Sie sagen zu uns: „Wir möchten unsere SQL-Abfragen überwachen. Diese haben nicht 255 Zeichen, sondern 8 MB jeder. Wir möchten sie in Grafana anzeigen, die Parameter dieser Abfrage sehen und noch besser, wir wollen die Top-Abfragen sehen. Es wäre großartig, wenn sie in Echtzeit angezeigt werden. Und es wäre richtig toll, sie in ein Alerting-System zu integrieren.“

Beispiel für eine SQL-Abfrage, die als Beispiel von
Wir setzen den Redis-Server in Betrieb und nutzen unsere Collectd-Plugins, die auf Postgres zugreifen und von dort alle Daten abholen, um die Metriken an Graphite zu senden. Dabei ersetzen wir den Metriknamen durch Hashes. Dieser Hash wird gleichzeitig als Schlüssel an Redis übermittelt, und die gesamte SQL-Abfrage dient als Wert. Nun bleibt uns nur noch, Grafana so einzurichten, dass es auf Redis zugreifen und diese Informationen abrufen kann. Wir öffnen die Graphite-API, da dies die Hauptschnittstelle für die Interaktion aller Überwachungsbestandteile mit Graphite ist, und implementieren eine neue Funktion namens aliasByHash(). Von Grafana erhalten wir den Metriknamen, den wir in der Anfrage an Redis als Schlüssel verwenden. Als Antwort erhalten wir den Wert des Schlüssels, der unsere "SQL-Abfrage" ist. Auf diese Weise haben wir in Grafana die Darstellung der SQL-Abfrage ermöglicht, die dort ursprünglich nicht angezeigt werden konnte, zusammen mit den dazugehörigen Statistiken (calls, rows, total_time, …).
Ergebnisse
Verfügbarkeit. Unser Überwachungsdienst ist rund um die Uhr aus jeder Anwendung und jedem Code verfügbar. Wenn Sie Zugriff auf die Speicherorte haben, können Sie Daten an den Dienst senden. Die Sprache ist unerheblich, die Lösungen sind nicht wichtig. Sie müssen nur wissen, wie Sie einen Socket öffnen, die Metrik hineinschicken und den Socket schließen.
Zuverlässigkeit. Alle Komponenten sind ausfallsicher und bewältigen unsere Lasten gut.
Niedrige Einstiegshürde. Um dieses System zu nutzen, müssen Sie keine Programmiersprachen oder Abfragen in Grafana lernen. Sie öffnen einfach Ihre Anwendung, geben den Socket ein, der Metriken an Graphite sendet, schließen sie, öffnen Grafana, erstellen dort Dashboards und beobachten das Verhalten Ihrer Metriken, während Sie über Moira Benachrichtigungen erhalten.
Eigenverantwortung. All dies können Sie selbstständig erledigen, ohne Hilfe von DevOps-Ingenieuren. Das ist übertrieben, denn Sie können Ihr Projekt jetzt sofort überwachen, ohne jemanden um Hilfe bitten zu müssen – weder für den Start noch für Änderungen.
Wohin streben wir?
Alles, was im Folgenden aufgeführt ist, sind nicht nur abstrakte Gedanken, sondern Dinge, zu denen bereits erste Schritte unternommen wurden.
- Anomalie-Detektor. Wir möchten einen Service entwickeln, der unsere Graphite-Speicher abklappert und jede Metrik nach verschiedenen Algorithmen überprüft. Es gibt bereits Algorithmen, die wir einsehen möchten, und wir haben Daten, mit denen wir arbeiten können.
- Metadaten. Wir bieten viele Dienste an, die sich im Laufe der Zeit ändern, ebenso wie die Menschen, die sie betreuen. Eine manuelle Dokumentation dauerhaft zu führen, ist keine Option. Deshalb integrieren wir jetzt Metadaten in unsere Mikrodienste. Dort wird festgehalten, wer sie entwickelt hat, mit welchen Sprachen sie interagieren, die SLA-Anforderungen und wohin sowie an wen Benachrichtigungen gesendet werden. Bei der Bereitstellung des Dienstes werden alle Entitätsdaten automatisch erstellt. Am Ende erhalten Sie zwei Links – einen zu den Triggern und einen zu den Dashboards in Grafana.
- Monitoring für jedes Zuhause. Wir sind der Meinung, dass alle Entwickler mit einem solchen System arbeiten sollten. So wissen Sie immer, wo sich Ihr Traffic befindet, was damit passiert, wo es Ausfälle gibt und wo Schwachstellen bestehen. Wenn beispielsweise etwas kommt und Ihren Dienst überlastet, erfahren Sie nicht während eines Anrufs von einem Manager darüber, sondern durch einen Alarm und können direkt die aktuellen Protokolle öffnen und nachsehen, was passiert ist.
- Hohe Leistung. Unser Projekt wächst kontinuierlich, und heute verarbeiten wir etwa 2.000.000 Metrikwerte pro Minute. Vor einem Jahr lag diese Zahl bei 500.000. Das Wachstum hält an, und das bedeutet, dass Graphite (whisper) bald die Speicher-Subsysteme stark belasten wird. Wie bereits erwähnt, ist dieses Überwachungssystem aufgrund der Modularität der Komponenten recht vielseitig. Während einige gezielt für Graphite ihre Infrastruktur pflegen und ständig erweitern, haben wir uns entschieden, einen anderen Weg zu gehen: Wir nutzen als Speicher für unsere Metriken. Dieser Übergang ist fast abgeschlossen, und bald werde ich näher erläutern, wie dies durchgeführt wurde: welche Herausforderungen es gab und wie wir sie überwunden haben, wie der Migrationsprozess ablief, und ich werde die gewählten Komponenten sowie deren Konfigurationen beschreiben.
Vielen Dank für Ihre Aufmerksamkeit! Stellen Sie Ihre Fragen zu diesem Thema, ich werde versuchen, sie hier oder in den nächsten Beiträgen zu beantworten. Vielleicht hat jemand Erfahrungen beim Aufbau eines solchen Überwachungssystems oder beim Umstieg auf Clickhouse in einer ähnlichen Situation – teilen Sie diese bitte in den Kommentaren.
Quelle: habr.com
