Présentation

La métrologie est une des briques fondamentales de la supervision. Pour superviser au mieux, voir venir les problèmes, ou aider les diagnostics, il est toujours bon de s'appuyer sur un maximum de métriques. Les métriques étant juste des valeurs représentant l'état de santé d'un élément précis (CPU, disques, débits réseaux etc), archivées sur une durée plus ou moins longue.

Il y a les outils ancestraux comme MRTG, RRD qui s'occupent déjà très bien de cette partie, et répondent bien à la nécessité d'avoir le plus de surveillance possible. Mais ils manquent tous de souplesse.

La pile logiciel « carbon-graphite » en permettant le stockage d'un ensemble le plus exhaustif possible de métriques, répond elle aussi très bien à ce besoin. Cependant elle offre bien plus, en permettant aussi l'exploitation de toutes ces métriques, une facilité de mise en oeuvre, et une souplesse d'exploitation très intéressante, idéale pour les environnements assez mouvants comme la virtualisation (ou cloud pour les marketeux). Tout cela avec une approche très KISS que j'adore.

kiss.jpg

Afin de pouvoir répondre à ces exigences, il a fallu définir :

  • un protocole le plus simple et le plus leger possible
  • le même concept pour le stockage des métriques
  • un outil efficace de manipulation des données (graphes, fonctions mathématiques, etc)

C'est ce que tente d'apporter l'ensemble « carbon-graphite ».

Le protocole d'envoi des métriques (carbon)

Le démon carbon qui collecte les métriques écoute par défaut sur le port 2003, en UDP. Mais il est possible de passer par TCP si besoin. Mais ça, c'est pas très important.

Le plus important c'est que le protocole pour remonter les métriques à carbon est des plus simples (Yeah KISS !). Il s'agit d'un protocole ASCII PLAIN TEXT, et ça, ça change tout ! Il est donc facilement lisible et utilisable (via netcat par ex, curl ou autres). La "trame" doit juste suivre ce formalisme :

nom.de.votre.metrique valeur [date]

Exemple plus parlant (le CPU 0 de mon serveur 01 est idle à 99%):

serveur01.cpu.0.idle 99

La date si elle est omise sera celle de la réception de la métrique. Sinon il suffit de la préciser au format timestamp unix. Facile ?

Ainsi il est très envisageable de développer une sonde en 1 ligne de shell :

echo "serveur01.cpu.0.idle 99" | nc -u serveur-carbon 2003

C'est tout. Vous venez au passage de coder votre première sonde pour Carbon ! Est-il techniquement possible de faire plus simple ??

Le stockage des métriques (whisper)

Il faut ensuite pouvoir facilement stocker ces métriques (KISS once again !). Sans avoir non plus de configuration ou autres gestes à faire pour ajouter de nouvelles métriques. C'est là aussi toute la souplesse de cette solution. Il est possible d'y voir une sorte de "métrologie à la demande".

Attention, si vous trouvez que j'utilise trop souvent le mot métrique, c'est normal, je suis payé à chacune de ses occurrences... (ahah si seulement...)

La partie "backend" qui s'occupe de stocker les métriques sur disque s'appelle "whisper".

Pour se faire, la métrique est passée à whisper qui va la découper de manière hiérarchique. C'est plus simple que ça en a l'air, en gros il va remplacer les "." par des "/" et voilà! Ainsi nous retrouverons le nom de notre métrique dans l’arborescence des fichiers générés par whisper et qui stockent nos données.

Imaginons que le répertoire racine de notre base whisper soit /var/lib/carbon/whisper, notre métrique de notre exemple précédent sera stockée dans /var/lib/carbon/whisper/server01/cpu/0/idle.wsp. Pour l'exploitation vu que l'arborescence des fichiers représente la structure de nos données, c'est simple à manipuler.

Ensuite concrètement, dans ce fichier wsp, il s'agit d'une structure de type Round Robin. Pour des raisons de performance, la structure complète du fichier est crée à la première réception de la métrique. La taille est donc fixe. La structure est très rigide et imposée, pour des questions de performances. De toute façon, les données sont toujours du même type (un nom, une valeur, une date). Si vous avez un besoin particulier de stocker autres choses en plus (tags etc), il faudra se pencher sur InfluxDB (entres autres).

A fonction du nombre de métriques que vous recevrez à l'instant T, il faut que votre disque puisse encaisser (en débit et en IO/s). Sinon les métriques ne pouvant être écrites à temps seront stockées en cache par carbon, et au bout d'un moment ça finira par déborder. Et c'est pas jolie.

Chaque métrique, peut se voir associer une granularité et une rétention. Il faudra donc commencer par se poser la question "Qu'est-ce que je souhaite stocker?" mais surtout "avec quelle précision, et sur quelle durée". Ces questions permettront aussi d'estimer la volumétrie nécessaire. (et non 42 n'est pas une réponse)

Finesse des mesures et période de rétention

Toujours en suivant notre exemple, imaginons que nous souhaitons garder les métriques récentes de manière assez précise, puis plus on s'éloignera dans le temps, moins nous aurons besoin de cette finesse. En général c'est assez vrai, il est rare d'avoir à se pencher sur des métriques très précises 5 ans après un problème etc. Ceci dit, si c'est votre besoin, c'est tout aussi possible.

Cette partie dans le vocabulaire "carbon/graphite" s'appelle la gestion des schémas de stockage.

Pour notre exemple, disons donc, 1 métrique toutes les 10 secondes, sur 1 mois, puis nous passerons à 1 métrique toutes les minutes sur 3 mois, puis 1 métrique toute les 5 minutes sur 1 an (noté 10s:1m,60s:90d:5m:1y dans la configuration whisper). Il est possible de continuer longtemps comme ça. Ce mécanisme de rétention est configuré dans /etc/carbon/storage-schemas.conf. Baisser la granularité au fil de temps permet aussi de réduire la taille des bases en faisant des concessions sur la granularité. Ce qui nous amène à une nouvelle question, comment estimer la taille de nos métriques ?

Cette configuration très souple de la granularité s'applique sur des expressions régulières visant le nom de la métrique. Ceci permet de configurer simplement des rétentions et granularités différentes en fonction du nom de la métrique. Encore une fois, cette configuration se fait dans le fichier /etc/carbon/storage-schemas.conf, qui est vérifié toutes les 60 secondes par carbon. Attention l'ordre dans ce fichier est important, la première correspondance trouvée est appliquée.

A chaque changement de granularité, il y a une opération de consolidation (ou agrégation), configurable, que nous verrons plus bas.

Estimation de la taille des métriques

Il faut être honnête, nous nous sommes pas trop griller les neurones jusqu'à présent. J'ai donc voulu pimenter cet article avec un peu de mathématique. Si vous êtes allergique aux maths, l'approche empirique de tester le stockage de métrique pour une machine "témoin", et de multiplier ça par le nombre de machines en cible fonctionne très bien. Mais vous pouvez quand même faire semblant et lire l'explication suivante...

dog_computer.jpg

Pour estimer la volumétrie, il faut savoir qu'un point de métrique pèse 12 octets (c'est loin d'être lourd, pas très heavy metal mais KISS tout de même !). Reprenons notre exemple de rétention (10s:1m,60s:90d:5m:1y) :

  • Pour les métriques à 10s sur 30 jours :
    • Nombre de secondes dans 1 mois : 30 jours * 24 heures * 60 minutes * 60 secondes = 2592000
    • 1 seul métrique par tranche de 10 seconde : 2592000 / 10 = 259200 points
  • Pour les métriques à 60s sur 90 jours :
    • Nombre de minutes dans 90 jours : 90 jours * 24 heures * 60 minutes = 129600 points
  • Pour les métriques à 5 minutes sur 1 an :
    • Nombre de minutes sur 1 an : 365 jours * 24 heures * 60 minutes = 525600
    • 1 métrique par tranche de 5 minutes : 525600 / 5 = 105120 points

Donc au total, 1 métrique vu nos rétentions aura au maximum 259 200 + 129 600 + 105 120 = 493 920 points. La taille approximative du fichier wsp correspondant sera donc de 5 Mo (493 920 * 12 octets). Il faut prévoir une petite entête dans chaque fichier.

Si vous avez 20 serveurs, avec 100 métriques chaques, on arrive vite à de beaux volumes : 20 * 100 * 5 Mo = 10 Gio. En divisant par 2 nos prétentions sur les granularités (10s:1m,60s:90d:5m:1y => 20s:1m,120s:90d,10m:1y), ce qui n'est pas non plus dramatique, nous divisons par 2 la volumétrie nécessaire (donc 5Gio).

Voilà pour une idée sur comment estimer la volumétrie nécessaire. Et comme par défaut les fichiers whisper sont à taille fixe, tant que vous n'ajoutez pas de nouvelles métriques, l'espace utilisé n'évoluera pas.

Agrégation lors d'un changement de granularité

Que fait carbon quand il reçoit une métrique ? Il cherche déjà à savoir quelle granularité lui appliquer, grâce à la configuration faite dans /etc/carbon/storage-schemas.conf. La métrique passe dans la partie whisper pour être enregistrée sur disque, et les différentes finesses vont être calculées.

Quand une métrique bascule d'un niveau de granularité à un autre, il y a consolidation (ou agrégation, aggregation en anglais, je suis bilingue). C'est à dire qu'il faut appliquer une méthode pour changer la granularité. Par défaut, il s'agit de faire une moyenne pour lisser la perte de finesse. Mais ceci est configurable, cette fois dans /etc/carbon/storage-aggregation.conf. Il faut aussi disposer d'assez de valeurs dans la finesse précédente sur les périodes qui se chevauchent. Ceci est configurable via le paramètre xFilesFactor (par défaut à 0.5 ce qui signife qu'il faut 50% des points). 

Ne vous inquiétez pas, les valeurs par défaut couvrent 90% des usages. Ce qu'il faut retenir:

  • A chaque changement de rétention, carbon/whisper fait des calculs (=coût CPU)
  • Pour ces calculs il faut disposer d'assez de points (évitez donc d'avoir des plages de rétentions inutilisées)
  • Pour eviter de drôle de résultats, il vaut mieux que les périodes soit des multiples entre elles (passer d'une métrique toutes les 10s à 1 par minutes c'est ok car on consolide les 6 dernières métriques, mais ko si 1 par 10s puis 1 par 55s, car comment consolider 5,5 dernières métriques??)

La visualisation des données (graphite)

Sans parler de cette partie, nous avons déjà un outils plutôt puissant, et assez simple à mettre en oeuvre et à comprendre. J'ajouterais en plus que le code est en python, donc facile à lire, et très réduit. Mais la pile carbon-graphite ne serait pas complète sans la partie visualisation des données, la partie "graphite" (graphique quoi).

Ce qui est assez intéressant avec le moteur graphite, c'est qu'il fournit en fait un moteur, interrogeable en HTTP, qui peut restituer les données brutes dans plein de formats (json, csv, etc), mais aussi des graphiques (en SVG, JPG etc), tout en ayant une bibliothèque assez large de fonctions mathématiques pour manipuler les données. A noter qu'avant, avec les outils ancestraux, il fallait trop souvent penser dès le début s'il fallait stocker des résultats mathématiques (moyenne, min/max etc). Ici au final, nous avons les métriques brutes, il est du coup possible de les manipuler comme il nous plait après coup. Bien plus simple.

Nous avons donc rien de particulier à faire si nous voulons avoir une moyenne, glissante ou pas, une valeur de percentile, un top 10, des déviants, et même des prédictions de tendance. Facilement utilisable via l'interface web proposée, ou en développant soi-même quelques petits scripts en javascripts (vu que ça cause JSON).
L'interface web proposée est pas si mal, avec peu être un look un peu old-school. Mais elle met facilement à disposition toutes les fonctions possibles et la navigation dans l'ensemble des métriques est simple. Il est même possible de définir des dashboards etc. Mais pour ce type d'usage plus évolué, nous verrons plutôt l'outil Grafana (qui était d'ailleurs à la base que du javascript devant le moteur graphite).

Conclusion

Au final cette solution de métrologie est très satisfaisante, facile à mettre en oeuvre (je ferais sûrement des billets la dessus), et tient la charge à condition d'avoir bien penser son architecture et surtout ses capacités de stockage.
A completer avec une centralisation des logs ELK (que j'ai déjà abordé ici mais c'est vieux) et c'est tout bon.