Verwendung von Prometheus zum Erkennen von Anomalien in GitLab


Eine der Grundfunktionen der Prometheus-Abfragesprache ist die Echtzeitaggregation von Zeitreihen . Sie können auch die Prometheus-Abfragesprache verwenden, um Anomalien in Zeitreihendaten zu erkennen. 

Das Mail.ru Cloud - Lösungen Team hat übersetzt einen Artikel von dem Ingenieure des Gitlab Infrastruktur - Teams , in dem Sie Codebeispiele finden , dass Sie auf Ihrem System ausprobieren können.

Wofür ist Anomalieerkennung?


Es gibt vier Hauptgründe, die die Bedeutung der Erkennung von Anomalien für GitLab bestimmen:

  1. Incident Diagnostics : Wir können erkennen, welche Dienste über ihren normalen Umfang hinausgegangen sind, indem wir die Incident Detection Time (MTTD) reduzieren und dementsprechend eine schnellere Lösung für das Problem anbieten.
  2. Erkennung von Leistungseinbußen : Wenn beispielsweise eine Regression in einen Dienst eingeführt wird, die dazu führt, dass dieser zu oft auf einen anderen Dienst zugreift, können wir dieses Problem schnell erkennen und beheben.
  3. Erkennung und Beseitigung von Missbrauch : GitLab bietet Bereitstellungs- und Integrationsmechanismen ( GitLab CI / CD ) und Hosting (GitLab Pages) sowie eine begrenzte Anzahl von Benutzern, die diese Mechanismen verwenden können.
  4. Sicherheit : Die Erkennung von Anomalien ist wichtig, um ungewöhnliche Trends in der GitLab-Zeitreihe zu erkennen.

Aus diesen und anderen Gründen hat der Autor des Artikels beschlossen, herauszufinden, wie die Definition von Anomalien in der GitLab-Zeitreihe mithilfe von Prometheus-Abfragen und -Regeln konfiguriert werden kann.

Was ist die richtige Aggregationsebene?


Erstens müssen Zeitreihen korrekt aggregiert werden. Im folgenden Beispiel haben wir den Standardzähler http_requests_total zum Abrufen von Daten verwendet, obwohl dies auch bei vielen anderen Metriken der Fall wäre.

http_requests_total{
 job="apiserver",
 method="GET",
 controller="ProjectsController",
 status_code="200",
 environment="prod"
}

Diese Testmetrik enthält mehrere Parameter: Methode, Controller, Statuscode (status_code), Umgebung sowie von Prometheus selbst hinzugefügte Parameter, z. B. Job und Instanz.

Jetzt müssen Sie die richtige Ebene der Datenaggregation auswählen. Zu viel, zu wenig - all dies ist wichtig, um Anomalien zu erkennen. Wenn die Daten zu aggregiert sind, gibt es zwei mögliche Probleme:

  1. Sie können die Anomalie überspringen, da durch die Aggregation Probleme ausgeblendet werden, die in Teilmengen Ihrer Daten auftreten.
  2. Wenn Sie eine Anomalie finden, ist es schwierig, sie ohne zusätzlichen Aufwand mit einem separaten Teil Ihres Systems in Verbindung zu bringen.

Wenn die Daten nicht ausreichend aggregiert sind, kann dies zu einer Erhöhung der Anzahl falsch positiver Ergebnisse sowie zu einer falschen Interpretation gültiger Daten als fehlerhaft führen.

Basierend auf unserer Erfahrung ist die korrekteste Aggregationsebene die Serviceebene, dh wir fügen das Label für Arbeit (Job) und Umgebung (Umgebung) hinzu und verwerfen alle anderen Labels.

Die Aggregation, die wir im gesamten Artikel diskutieren werden, umfasst: job - http_request, Aggregation - fünf Minuten, die auf der Grundlage von Arbeit und Umgebung in fünf Minuten berechnet wird.

- record: job:http_requests:rate5m
expr: sum without(instance, method, controller, status_code)
(rate(http_requests_total[5m]))
# --> job:http_requests:rate5m{job="apiserver", environment="prod"}  21321
# --> job:http_requests:rate5m{job="gitserver", environment="prod"}  2212
# --> job:http_requests:rate5m{job="webserver", environment="prod"}  53091

Aus dem obigen Beispiel geht hervor, dass aus der Reihe http_requests_total-Teilmengen im Kontext von Arbeit und Umgebung ausgewählt werden und ihre Anzahl dann fünf Minuten lang berücksichtigt wird.

Verwenden des Z-Scores zum Erkennen von Anomalien


Die Grundprinzipien der Statistik können angewendet werden, um Anomalien zu erkennen.

Wenn Sie den Mittelwert und die Standardabweichung der Prometheus-Reihe kennen, können Sie eine beliebige Stichprobe in der Reihe verwenden, um den Z-Score zu berechnen. 

Ein Z-Score ist ein Maß für die relative Streuung des beobachteten oder gemessenen Werts, das zeigt, wie viele Standardabweichungen seine Streuung relativ zum Durchschnittswert beträgt

Das heißt, der Z-Score = 0 bedeutet, dass der Z-Score mit dem Durchschnittswert im Datensatz mit der Standardverteilung identisch ist, und der Z-Score = 1 bedeutet, dass die Standardabweichung = 1,0 vom Durchschnitt ist.

Wir gehen davon aus, dass die Basisdaten eine Normalverteilung haben, was bedeutet, dass 99,7% der Stichproben einen Z-Score von 0 bis 3 haben. Je weiter der Z-Score von Null entfernt ist, desto unwahrscheinlicher ist seine Existenz. 

Wir wenden diese Eigenschaft an, um Anomalien in der Prometheus-Datenreihe zu erkennen:

  1. Wir berechnen den Mittelwert und die Standardabweichung für die Metrik anhand von Daten mit einer großen Stichprobengröße. In diesem Beispiel verwenden wir wöchentliche Daten. Wenn wir davon ausgehen, dass die Aufzeichnungen einmal pro Minute ausgewertet werden, werden wir in einer Woche etwas mehr als 10.000 Proben haben.

    # Long-term average value for the series
    - record: job:http_requests:rate5m:avg_over_time_1w
    expr: avg_over_time(job:http_requests:rate5m[1w])
    
    # Long-term standard deviation for the series
    - record: job:http_requests:rate5m:stddev_over_time_1w
    expr: stddev_over_time(job:http_requests:rate5m[1w])

  2. Wir können den Z-Score für die Prometheus-Abfrage berechnen, sobald wir den Mittelwert und die Standardabweichung für die Aggregation erhalten.

    # Z-Score for aggregation
    (
    job:http_requests:rate5m -
    job:http_requests:rate5m:avg_over_time_1w
    ) /  job:http_requests:rate5m:stddev_over_time_1w


Angenommen, basierend auf den statistischen Prinzipien von Normalverteilungen ist jeder Wert außerhalb des Bereichs von +3 bis -3 eine Anomalie. Dementsprechend können wir eine Warnung vor solchen Anomalien erstellen. Beispielsweise erhalten wir eine Benachrichtigung, wenn unsere Aggregation länger als fünf Minuten über diesen Bereich hinausgeht.


Diagramm der Anzahl der Anfragen pro Sekunde an den GitLab Pages-Dienst für 48 Stunden. Der Z-Score im Bereich von +3 bis -3 wird grün hervorgehoben. Der

Z-Score kann in den Diagrammen schwierig zu interpretieren sein, da dieser Wert keine Maßeinheit hat. Die Anomalien in diesem Diagramm sind jedoch sehr einfach zu bestimmen. Alles, was über die grüne Zone hinausgeht, die einen Wertekorridor mit einem Z-Score von -3 bis +3 anzeigt, ist ein anomaler Wert.

Was tun, wenn die Datenverteilung nicht normal ist?


Wir gehen davon aus, dass die Datenverteilung normal ist. Andernfalls ist unser Z-Score falsch.

Es gibt viele statistische Tricks, um die Normalität der Datenverteilung zu bestimmen. Am besten überprüfen Sie jedoch, ob Ihr Daten-Z-Score im Bereich von -4,0 bis +4,0 liegt.

Zwei Prometheus-Abfragen mit minimalen und maximalen Z-Scores:

(
max_over_time(job:http_requests:rate5m[1w]) - avg_over_time(job:http_requests:rate5m[1w])
) / stddev_over_time(job:http_requests:rate5m[1w])
# --> {job="apiserver", environment="prod"}  4.01
# --> {job="gitserver", environment="prod"}  3.96
# --> {job="webserver", environment="prod"}  2.96

(
 min_over_time(job:http_requests:rate5m[<1w]) - avg_over_time(job:http_requests:rate5m[1w])
) / stddev_over_time(job:http_requests:rate5m[1w])
# --> {job="apiserver", environment="prod"}  -3.8
# --> {job="gitserver", environment="prod"}  -4.1
# --> {job="webserver", environment="prod"}  -3.2

Wenn Ihre Ergebnisse im Bereich von -20 bis +20 liegen, bedeutet dies, dass zu viele Daten verwendet wurden und die Ergebnisse verzerrt sind. Denken Sie auch daran, dass Sie mit aggregierten Zeilen arbeiten müssen. Metriken ohne Normalverteilung enthalten Parameter wie Fehlerrate, Verzögerung, Warteschlangenlängen usw. Viele dieser Metriken funktionieren jedoch besser mit festen Alarmschwellenwerten.

Statistische Erkennung von Saisonalitätsanomalien


Obwohl die Berechnung von Z-Scores mit der Normalverteilung von Zeitreihendaten gut funktioniert, gibt es eine zweite Methode, mit der sich noch genauere Anomalieerkennungsergebnisse erzielen lassen. Dies ist die Verwendung der statistischen Saisonalität. 

Saisonalität ist ein Merkmal einer Zeitreihenmetrik, wenn diese Metrik regelmäßigen und vorhersehbaren Änderungen unterliegt, die in jedem Zyklus wiederholt werden.


Diagramm der Anfragen pro Sekunde (RPS) von Montag bis Sonntag für vier aufeinanderfolgende Wochen Das

Diagramm oben zeigt das RPS (Anzahl der Anfragen pro Sekunde) für sieben Tage - von Montag bis Sonntag für vier aufeinanderfolgende Wochen. Dieser Bereich von sieben Tagen wird als "Versatz" bezeichnet, dh das Muster, das für die Messung verwendet wird.

Jede Woche auf dem Diagramm hat eine andere Farbe. Die Saisonalität der Daten wird durch die Reihenfolge in den in der Grafik angegebenen Trends angezeigt. Jeden Montagmorgen beobachten wir einen ähnlichen Anstieg des RPS, und abends am Freitag beobachten wir immer einen Rückgang des RPS.

Mithilfe der Saisonalität in unseren Zeitreihendaten können wir das Auftreten von Anomalien und deren Erkennung genauer vorhersagen. 

Wie man Saisonalität benutzt


Prometheus verwendet verschiedene statistische Mechanismen, um die Saisonalität zu berechnen.

Zunächst führen wir eine Berechnung durch und fügen den Ergebnissen der Vorwoche einen Wachstumstrend für die Woche hinzu. Der Wachstumstrend wird wie folgt berechnet: Subtrahieren Sie den gleitenden Durchschnitt der letzten Woche vom gleitenden Durchschnitt der letzten Woche.

- record: job:http_requests:rate5m_prediction
  expr: >
    job:http_requests:rate5m offset 1w          # Value from last period
    + job:http_requests:rate5m:avg_over_time_1w # One-week growth trend
    — job:http_requests:rate5m:avg_over_time_1w offset 1w

Die erste Iteration stellt sich als etwas „eng“ heraus - wir verwenden das Fünf-Minuten-Fenster dieser Woche und der Vorwoche, um unsere Prognosen zu erhalten.

Bei der zweiten Iteration erweitern wir unsere Abdeckung, indem wir den Durchschnitt des Vier-Stunden-Zeitraums der Vorwoche mit der aktuellen Woche vergleichen. 

Wenn wir also versuchen, den Metrikwert am Montag um acht Uhr morgens vorherzusagen, anstatt des gleichen Fünf-Minuten-Fensters in der Woche zuvor, nehmen wir den Durchschnittswert der Metrik von sechs auf zehn am Morgen des vorherigen Montags.

- record: job:http_requests:rate5m_prediction
  expr: >
    avg_over_time(job:http_requests:rate5m[4h] offset 166h) # Rounded value from last period
    + job:http_requests:rate5m:avg_over_time_1w    # Add 1w growth trend
    - job:http_requests:rate5m:avg_over_time_1w offset 1w

In der Anfrage wurden 166 Stunden angegeben, was zwei Stunden weniger als eine volle Woche ist (7 * 24 = 168), da wir einen Zeitraum von vier Stunden basierend auf der aktuellen Zeit verwenden möchten, sodass der Offset zwei Stunden weniger als eine volle Woche betragen muss. 


Realer RPS (gelb) und vorhergesagter (blau) in zwei Wochen

Ein Vergleich des tatsächlichen RPS mit unserer Prognose zeigt, dass unsere Berechnungen ziemlich genau waren. Diese Methode hat jedoch einen Nachteil.
 
Zum Beispiel wurde GitLab am 1. Mai mittwochs weniger als gewöhnlich verwendet, da dieser Tag ein freier Tag war. Da der geschätzte Wachstumstrend davon abhängt, wie das System in der Vorwoche verwendet wurde, ergaben unsere Prognosen für die nächste Woche, dh am Mittwoch, dem 8. Mai, einen niedrigeren RPS als tatsächlich.

Dieser Fehler kann korrigiert werden, indem drei Prognosen für drei aufeinanderfolgende Wochen vor Mittwoch, dem 1. Mai, dh den drei vorhergehenden Mittwochs, erstellt werden. Die Anforderung bleibt gleich, aber der Offset wird angepasst.

- record: job:http_requests:rate5m_prediction
  expr: >
   quantile(0.5,
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 166h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 1w
       , "offset", "1w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 334h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 2w
       , "offset", "2w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 502h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 3w
       , "offset", "3w", "", "")
   )
   without (offset)


Es gibt drei Prognosen für drei Wochen vor dem 8. Mai auf dem Chart, verglichen mit dem tatsächlichen RPS für Mittwoch, den 8. Mai. Sie können sehen, dass die beiden Prognosen sehr genau sind, aber die Prognose für die Woche vom 1. Mai bleibt ungenau.

Außerdem benötigen wir keine drei Prognosen, sondern eine Prognose. Der Durchschnittswert ist keine Option, da er durch unsere verzerrten RPS-Daten ab dem 1. Mai unscharf wird. Stattdessen müssen Sie den Median berechnen. Prometheus hat keine Medianabfrage, aber wir können anstelle des Medians die Quantilaggregation verwenden.

Das einzige Problem ist, dass wir versuchen, drei Serien in die Aggregation aufzunehmen, und diese drei Serien sind in drei Wochen tatsächlich die gleichen Serien. Mit anderen Worten, sie haben die gleichen Bezeichnungen, daher ist es schwierig, sie zusammenzusetzen. 

Um Verwirrung zu vermeiden, erstellen wir ein Etikett mit dem Namen Offset und verwenden die Funktion zum Ersetzen von Etiketten, um jeder der drei Wochen einen Versatz hinzuzufügen. Dann verwerfen wir bei der Quantilaggregation diese Markierungen, und dies ergibt einen Durchschnitt von drei.

- record: job:http_requests:rate5m_prediction
  expr: >
   quantile(0.5,
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 166h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 1w
       , "offset", "1w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 334h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 2w
       , "offset", "2w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 502h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 3w
       , "offset", "3w", "", "")
   )
   without (offset)

Jetzt ist unsere Prognose mit einem Median von drei Aggregationen genauer geworden.


Medianprognose im Vergleich zum tatsächlichen RPS

So finden Sie heraus, dass unsere Prognose wirklich genau ist


Um die Genauigkeit der Prognose zu überprüfen, können wir zum Z-Score zurückkehren. Es wird verwendet, um die Diskrepanz der Stichprobe mit ihrer Prognose in Standardabweichungen zu messen. Je größer die Standardabweichung von der Prognose ist, desto höher ist die Wahrscheinlichkeit, dass ein bestimmter Wert ein Ausreißer ist.


Der projizierte Abweichungsbereich liegt zwischen +1,5 und -1,5.

Sie können unser Grafana-Diagramm so ändern, dass anstelle eines wöchentlichen gleitenden Durchschnitts eine saisonale Prognose verwendet wird. Der Bereich der Normalwerte für eine bestimmte Tageszeit ist grün schattiert. Alles, was über die grüne Zone hinausgeht, gilt als Ausreißer. In diesem Fall trat der Ausreißer am Sonntagnachmittag auf, als unser Cloud-Anbieter einige Netzwerkprobleme hatte.

Es wird empfohlen, für saisonale Vorhersagen einen ± 2-Z-Score zu verwenden.

So richten Sie Benachrichtigungen mit Prometheus ein


Wenn Sie eine Warnung für abnormale Ereignisse einrichten möchten, können Sie die relativ einfache Prometheus-Regel anwenden, mit der überprüft wird, ob der Z-Score eines Indikators im Bereich zwischen +2 und -2 liegt.

- alert: RequestRateOutsideNormalRange
  expr: >
   abs(
     (
       job:http_requests:rate5m - job:http_requests:rate5m_prediction
     ) / job:http_requests:rate5m:stddev_over_time_1w
   ) > 2
  for: 10m
  labels:
    severity: warning
  annotations:
    summary: Requests for job {{ $labels.job }} are outside of expected operating parameters

In GitLab verwenden wir eine benutzerdefinierte Routing-Regel, die eine Warnung über Slack sendet, wenn Anomalien festgestellt werden, unser Support-Team jedoch nicht kontaktiert.

So erkennen Sie Anomalien in GitLab mit Prometheus


  1. Prometheus kann verwendet werden, um einige Anomalien zu erkennen.
  2. Die richtige Aggregation ist der Schlüssel zum Auffinden von Anomalien.
  3. Z-Scoring ist effektiv, wenn Ihre Daten normal verteilt sind.
  4. Die statistische Saisonalität ist ein leistungsfähiger Mechanismus zur Erkennung von Anomalien.

Übersetzt mit Unterstützung von Mail.ru Cloud Solutions .

Immer noch nützlich :

  1. Einfache Caching-Methoden in GitLab CI: Ein Bildhandbuch .
  2. Vorgefertigte und angepasste GitLab CE-Tools auf dem MCS-Marktplatz
  3. Unser Telegrammkanal zur digitalen Transformation .

All Articles