Comment utiliser Prometheus pour détecter des anomalies dans GitLab


L'une des caractĂ©ristiques de base du langage de requĂŞte Prometheus est l' agrĂ©gation en temps rĂ©el des sĂ©ries chronologiques . Vous pouvez Ă©galement utiliser le langage de requĂŞte Prometheus pour dĂ©tecter les anomalies dans les donnĂ©es de sĂ©ries chronologiques. 

L'équipe Mail.ru Cloud Solutions a traduit un article de l'ingénieur de l'équipe d'infrastructure GitLab , où vous trouverez des exemples de code que vous pouvez essayer sur vos systèmes.

À quoi sert la détection des anomalies?


Il existe quatre raisons principales qui déterminent l'importance de la détection d'anomalies pour GitLab:

  1. Diagnostic des incidents : nous pouvons détecter les services qui ont dépassé leur portée normale en réduisant le temps de détection des incidents (MTTD) et, en conséquence, offrir une solution plus rapide au problème.
  2. Détection de la dégradation des performances : par exemple, si une régression est introduite dans un service qui lui fait accéder trop souvent à un autre service, nous pouvons rapidement détecter et résoudre ce problème.
  3. Détection et élimination des abus : GitLab fournit des mécanismes de livraison et d'intégration ( GitLab CI / CD ) et d'hébergement (GitLab Pages) et un nombre limité d'utilisateurs qui peuvent utiliser ces mécanismes.
  4. Sécurité : la détection des anomalies est importante pour détecter les tendances inhabituelles dans la série chronologique GitLab.

Pour ces raisons et d'autres, l'auteur de l'article a décidé de comprendre comment configurer la définition des anomalies dans la série temporelle GitLab à l'aide des requêtes et des règles de Prometheus.

Quel est le niveau d'agrégation correct?


Tout d'abord, les séries chronologiques doivent être correctement agrégées. Dans l'exemple ci-dessous, nous avons utilisé le compteur http_requests_total standard pour récupérer des données, bien que de nombreuses autres mesures le fassent également.

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

Cette mesure de test comporte plusieurs paramètres: méthode, contrôleur, code d'état (code_état), environnement, ainsi que des paramètres ajoutés par Prometheus lui-même, par exemple, travail et instance.

Vous devez maintenant choisir le bon niveau d'agrégation de données. Trop, trop peu - tout cela est important pour détecter les anomalies. Si les données sont trop agrégées, il y a deux problèmes potentiels:

  1. Vous pouvez ignorer l'anomalie car l'agrégation masque les problèmes qui se produisent dans des sous-ensembles de vos données.
  2. Si vous trouvez une anomalie, il est difficile de la relier à une partie distincte de votre système sans effort supplémentaire.

Si les données ne sont pas suffisamment agrégées, cela peut conduire à une augmentation du nombre de faux positifs, ainsi qu'à une interprétation incorrecte des données valides comme erronées.

D'après notre expérience, le niveau d'agrégation le plus correct est le niveau de service, c'est-à-dire que nous incluons l'étiquette de travail (travail) et d'environnement (environnement) et rejetons toutes les autres étiquettes.

L'agrégation, dont nous parlerons tout au long de l'article, comprend: travail - http_request, agrégation - cinq minutes, qui est calculé sur la base du travail et de l'environnement en cinq minutes.

- 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

D'après l'exemple ci-dessus, il est clair que dans la série http_requests_total, les sous-ensembles sont sélectionnés dans le contexte du travail et de l'environnement, puis leur nombre est considéré pendant cinq minutes.

Utilisation du score Z pour détecter les anomalies


Les principes de base des statistiques peuvent être appliqués pour détecter des anomalies.

Si vous connaissez la moyenne et l' Ă©cart type de la sĂ©rie Prometheus, vous pouvez utiliser n'importe quel Ă©chantillon de la sĂ©rie pour calculer le z-score. 

Un Z-score est une mesure de l'écart relatif de la valeur observée ou mesurée, qui montre combien d' écarts-types son écart par rapport à la valeur moyenne est

Autrement dit, le score z = 0 signifie que le score z est identique à la valeur moyenne dans l'ensemble de données avec la distribution standard, et le score z = 1 signifie que l'écart type = 1,0 de la moyenne.

Nous supposons que les donnĂ©es de base ont une distribution normale, ce qui signifie que 99,7% des Ă©chantillons ont un score z de 0 Ă  3. Plus le score z est Ă©loignĂ© de zĂ©ro, moins il est probable qu'il existe. 

Nous appliquons cette propriété pour détecter les anomalies dans la série de données Prometheus:

  1. Nous calculons la moyenne et l'écart type de la métrique à l'aide de données avec un échantillon de grande taille. Pour cet exemple, nous utilisons des données hebdomadaires. Si nous supposons que les enregistrements sont évalués une fois par minute, alors dans une semaine, nous aurons un peu plus de 10 000 échantillons.

    # 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. Nous pouvons calculer le z-score pour la requête Prometheus dès que nous obtenons la moyenne et l'écart-type pour l'agrégation.

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


Sur la base des principes statistiques des distributions normales, supposons que toute valeur en dehors de la plage de +3 à -3 sera une anomalie. En conséquence, nous pouvons créer un avertissement concernant de telles anomalies. Par exemple, nous recevrons une alerte lorsque notre agrégation dépasse cette plage pendant plus de cinq minutes.


Graphique du nombre de requêtes par seconde au service GitLab Pages pendant 48 heures. Le score Z compris entre +3 et -3 est surligné en vert. Le

score Z peut être difficile à interpréter sur les graphiques, car cette valeur n'a pas d'unité de mesure. Mais les anomalies de ce graphique sont très simples à déterminer. Tout ce qui va au-delà de la zone verte, qui montre un couloir de valeurs avec un z-score de -3 à +3, sera une valeur anormale.

Que faire si la distribution des données n'est pas normale


Nous supposons que la distribution des données est normale. Sinon, notre z-score sera faux.

Il existe de nombreuses astuces statistiques pour déterminer la normalité de la distribution des données, mais le meilleur moyen est de vérifier que le score z de vos données se situe dans la plage de -4,0 à +4,0.

Deux requĂŞtes Prometheus montrant les scores z minimum et maximum:

(
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

Si vos résultats sont compris entre -20 et +20, cela signifie que trop de données ont été utilisées et les résultats sont déformés. N'oubliez pas également que vous devez travailler avec des lignes agrégées. Les mesures qui n'ont pas de distribution normale incluent des paramètres tels que le taux d'erreur, le retard, la longueur des files d'attente, etc. Mais bon nombre de ces mesures fonctionneront mieux avec des seuils d'alerte fixes.

Détection statistique d'anomalies saisonnières


Bien que le calcul des scores z fonctionne bien avec la distribution normale des donnĂ©es de sĂ©ries chronologiques, il existe une deuxième mĂ©thode qui peut donner des rĂ©sultats de dĂ©tection d'anomalies encore plus prĂ©cis. C'est l'utilisation de la saisonnalitĂ© statistique. 

La saisonnalité est une caractéristique d'une métrique de série chronologique lorsque cette métrique subit des changements réguliers et prévisibles qui se répètent à chaque cycle.


Graphique des demandes par seconde (RPS) du lundi au dimanche pendant quatre semaines consécutives Le

graphique ci-dessus illustre le RPS (nombre de demandes par seconde) pendant sept jours - du lundi au dimanche, pendant quatre semaines consécutives. Cette plage de sept jours est appelée «décalage», c'est-à-dire le motif qui sera utilisé pour la mesure.

Chaque semaine sur le graphique est d'une couleur différente. La saisonnalité des données est indiquée par la séquence des tendances indiquées sur le graphique - chaque lundi matin, nous observons une augmentation similaire du RPS, et le soir, le vendredi, nous observons toujours une diminution du RPS.

En utilisant la saisonnalitĂ© dans nos donnĂ©es de sĂ©ries chronologiques, nous pouvons prĂ©dire avec plus de prĂ©cision l'occurrence des anomalies et leur dĂ©tection. 

Comment utiliser la saisonnalité


Prométhée utilise plusieurs mécanismes statistiques différents pour calculer la saisonnalité.

Tout d'abord, nous faisons un calcul, en ajoutant une tendance de croissance pour la semaine aux résultats de la semaine précédente. La tendance de croissance est calculée comme suit: soustrayez la moyenne mobile de la semaine dernière de la moyenne mobile de la semaine dernière.

- 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

La première itération s'avère quelque peu «étroite» - nous utilisons la fenêtre de cinq minutes de cette semaine et de la semaine précédente pour obtenir nos prévisions.

Ă€ la deuxième itĂ©ration, nous Ă©largissons notre couverture en prenant la moyenne de la pĂ©riode de quatre heures pour la semaine prĂ©cĂ©dente et en la comparant avec la semaine en cours. 

Ainsi, si nous essayons de prédire la valeur métrique à huit heures du matin le lundi, au lieu de la même fenêtre de cinq minutes la semaine précédente, nous prenons la valeur moyenne de la mesure de six à dix le matin du lundi précédent.

- 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

La demande indiquait 166 heures, soit deux heures de moins qu'une semaine complète (7 * 24 = 168), car nous voulons utiliser une pĂ©riode de quatre heures en fonction de l'heure actuelle, nous avons donc besoin que le dĂ©calage soit de deux heures infĂ©rieur Ă  une semaine complète. 


RPS réel (jaune) et prévu (bleu) dans deux semaines

Une comparaison du RPS réel avec nos prévisions montre que nos calculs étaient assez précis. Cependant, cette méthode présente un inconvénient.
 
Par exemple, le 1er mai, GitLab a été utilisé moins que d'habitude le mercredi, car ce jour était un jour de congé. Étant donné que la tendance de croissance estimée dépend de la façon dont le système a été utilisé la semaine précédente, nos prévisions pour la semaine prochaine, c'est-à-dire le mercredi 8 mai, ont donné un RPS inférieur à la réalité.

Cette erreur peut être corrigée en faisant trois prévisions pour trois semaines consécutives avant le mercredi 1er mai, c'est-à-dire les trois mercredi précédent. La demande reste la même, mais le décalage est ajusté.

- 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)


Il y a trois prévisions sur le graphique pour trois semaines avant le 8 mai, par rapport au RPS réel du mercredi 8 mai. Vous pouvez voir que les deux prévisions sont très précises, mais les prévisions pour la semaine du 1er mai restent inexactes.

De plus, nous n'avons pas besoin de trois prévisions, nous avons besoin d'une seule prévision. La valeur moyenne n'est pas une option, car elle sera floue par nos données RPS déformées du 1er mai. Au lieu de cela, vous devez calculer la médiane. Prométhée n'a pas de requête médiane, mais nous pouvons utiliser l'agrégation quantile au lieu de la médiane.

Le seul problème est que nous essayons d'inclure trois sĂ©ries dans l'agrĂ©gation, et ces trois sĂ©ries sont en fait la mĂŞme sĂ©rie en trois semaines. En d'autres termes, ils ont les mĂŞmes Ă©tiquettes, il est donc difficile de les assembler. 

Pour éviter toute confusion, nous créons une étiquette appelée décalage et utilisons la fonction de remplacement d'étiquette pour ajouter un décalage à chacune des trois semaines. Ensuite, dans l'agrégation quantile, nous rejetons ces étiquettes, ce qui nous donne une moyenne de trois.

- 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)

Maintenant, nos prévisions avec une médiane de trois agrégations sont devenues plus précises.


Prévision médiane par rapport au RPS réel

Comment savoir si nos prévisions sont vraiment précises


Pour vérifier l'exactitude des prévisions, nous pouvons revenir au z-score. Il est utilisé pour mesurer l'écart de l'échantillon avec sa prévision en écarts-types. Plus l'écart-type est important par rapport à la prévision, plus la probabilité qu'une valeur particulière soit une valeur aberrante est élevée.


La plage d'écart projetée est de +1,5 à -1,5.

Vous pouvez modifier notre graphique Grafana pour utiliser une prévision saisonnière, plutôt qu'une moyenne mobile hebdomadaire. La plage de valeurs normales pour une heure spécifique de la journée est ombrée en vert. Tout ce qui dépasse la zone verte est considéré comme une valeur aberrante. Dans ce cas, la valeur aberrante s'est produite dimanche après-midi, lorsque notre fournisseur de cloud a eu des problèmes de réseau.

Il est recommandé d'utiliser un score z ± 2 pour les prévisions saisonnières.

Comment configurer des alertes avec Prometheus


Si vous souhaitez configurer une alerte pour les événements anormaux, vous pouvez appliquer la règle assez simple de Prométhée, qui vérifie si le score z d'un indicateur est compris entre +2 et -2.

- 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

Dans GitLab, nous utilisons une règle de routage personnalisée qui envoie une alerte via Slack lorsqu'il détecte des anomalies, mais ne contacte pas notre équipe d'assistance.

Comment détecter les anomalies dans GitLab en utilisant Prometheus


  1. Prométhée peut être utilisé pour détecter certaines anomalies.
  2. Une bonne agrégation est la clé pour trouver des anomalies.
  3. Le score Z est efficace si vos données ont une distribution normale.
  4. La saisonnalité statistique est un puissant mécanisme de détection des anomalies.

Traduit avec le support de Mail.ru Cloud Solutions .

Toujours utile :

  1. MĂ©thodes de mise en cache simples dans GitLab CI: un guide d'images .
  2. Outils GitLab CE prêts à l'emploi et personnalisés sur le marché MCS
  3. Notre chaîne Telegram sur la transformation numérique .

All Articles