Graphite est un outil pour grapher différentes métriques qui peuvent être aussi bien des indicateurs systèmes (utilisation CPU, espace disque disponible, etc …), des indicateurs applicatifs (utilisation de la heap d’une JVM, requêtes par secondes d’une base de données, etc.) ou des indicateurs métiers exposés en JMX par exemple. Théoriquement, il n’y a pas de limite aux informations qui peuvent être stockées dans Graphite du moment qu’il s’agit de données numériques. Il est très facile de créer ses propres indicateurs.
Si l’installation basique de Graphite est relativement aisée, les choses deviennent un peu plus complexes lorsqu’il s’agit d’optimiser l’installation et de comprendre son comportement interne pour l’adapter à vos besoins.
Dans cet article je parlerai uniquement des mécanismes de Graphite et de son installation dans un environnement mono-serveur. La montée en charge et la haute disponibilité ainsi que les outils s’appuyant sur Graphite feront l’objet d’articles ultérieurs.
Les mécanismes de base
Lors de l’installation initiale de Graphite, on se retrouve vite perdu dans les différents éléments à installer ainsi dans le grand nombre de fichiers de configuration différents. Il est donc important de faire le point sur le mode de fonctionnement interne de Graphite.
Les composants de Graphite
Graphite est une application codée en Python, qui est composé de trois éléments distincts.
Carbon
Il s’agit du ou des processus qui vont être responsables de la collecte des métriques. Le premier qui se nomme Carbon est composé de trois daemons :
- carbon-cache.py : Processus qui collecte les données afin de les stocker par la suite. Il écoute par défaut sur les ports 2003 et/ou 2004.
- carbon-relay.py : Processus facultatif qui permet à Graphite de répliquer et de répartir les données entre plusieurs carbon-cache.py.
- carbon-aggregator.py : Processus facultatif qui permet de bufferiser et d’agréger les données en amont du carbon-cache.py afin de limiter les écritures de données et ainsi réduire les IO qui sont en règle générale le premier facteur limitant.
Dans une installation basique mono-serveur, seul le processus carbon-cache.py est utilisé.
Whisper
Il s’agit de la base de données de type fichier à taille fixe utilisée pour stocker les métriques. Whisper est comparable à RRD (Round Robin Database) et fournit à la fois une bibliothèque Python utilisée par Carbon et des outils en ligne de commande afin de manipuler les fichiers de données.
Graphite Webapp
Comme son nom l’indique, il s’agit de l’application web, écrite en Python et utilisable avec Apache (ou autre serveur HTTP) via le module WSGI.
L’application accède aux données provenant de Whisper et les affiche sous la forme de graphiques et de tableaux de bord.
Une base de données est nécessaire pour stocker uniquement les préférences utilisateurs et la sauvegarde des graphiques et des tableaux de bord. Par défaut, SQLite est utilisée, mais il est possible d’utiliser MySQL. Au vu de la faible volumétrie de données stockées, SQLite répond au besoin pour une installation mono-serveur.
Les protocoles
Plusieurs protocoles sont disponibles pour envoyer des informations vers Graphite.
Texte brut
Il s’agit du protocole standard le plus simple à utiliser. Le port par défaut pour envoyer des données en texte brut est le 2003.
Le format d’un message est le suivant :
<path.de.la.metrique> <value> <timestamp (epoch in second)>
Il est très facile d’envoyer des messages dans ce format grâce à nc ou à un programme de quelques lignes de codes : il suffit d’écrire des chaînes de caractères dans une socket.
Pickle
Dans ce protocole utilisant le port 2004 par défaut, l’objectif est de bufferiser les données afin de les envoyer par lot (avec une limite à 500 métriques environ afin d’éviter de dépasser les 1Mo/message).
Pour ce faire, Graphite utilise le mécanisme de “pickle” qui peut être considéré comme la sérialisation interne de Python. Ainsi, il est très délicat d’utiliser ce protocole avec un programme écrit dans un autre langage.
Le format des messages, avant sérialisation, est le suivant :
[(path, (timestamp, value)), ...] avec la taille du message comme entête.
AMQP
AMQP (pour Advanced Message Queuing Protocol, RabbitMQ par exemple) peut également être utilisé comme source de données. Dans ce cas, deux options sont disponibles :
-
Le nom de la métrique est dans le routing key et le message a le format suivant :
<value> <timestamp>
-
Le nom de la métrique est directement dans le message :
<metric.path> <value> <timestamp>
Les métriques
Chaque métrique est stockée dans son propre fichier qui par défaut a une taille fixe : il sera créé et alloué automatiquement lors de la première utilisation. Il est assez facile d’estimer l’occupation totale sur le système de fichiers.
Les métriques sont définies par un “chemin” séparé par des points. Par exemple :
servers.<nom-serveur>.cpu.total.idle servers.<nom-serveur>.diskspace.root.byte_avail
Le répertoire de stockage des métriques par défaut est /opt/graphite/storage/whisper et l’extension des fichiers utilisée est .wsp.
Installation mono-serveur
Dans cet article, nous allons faire l’installation de Graphite sur Amazon EC2 avec des distributions de type Amazon Linux qui sont basées sur des Red-Hat. Il est facile de faire le même type d’installation sur toute autre distribution où la principale différence résidera dans le nom des packages nécessaires.
Afin de générer du trafic, j’utilise Diamond qui est un outil pour collecter différentes métriques et ayant de nombreux plugins (collector). De base, seules les informations systèmes sont reportées.
Une fois connecté sur le serveur, l’installation à partir des binaires disponibles sur Launchpad est assez rapide. Lors de la rédaction de cet article, la dernière version stable de Graphite est la 0.9.10.
# Installation des packages nécessaires (valable pour Redhat/CentOS/etc...) sudo yum install django-tagging Django python-zope-interface pycairo python-twisted httpd mod_wsgi --enablerepo=epel mkdir /tmp/graphite #Installation de Carbon cd /tmp/graphite/ wget https://launchpad.net/graphite/0.9/0.9.10/+download/carbon-0.9.10.tar.gz tar xzf carbon-0.9.10.tar.gz cd carbon-0.9.10 sudo python setup.py install # Installation de Whisper cd /tmp/graphite/ wget https://launchpad.net/graphite/0.9/0.9.10/+download/whisper-0.9.10.tar.gz tar xzf whisper-0.9.10.tar.gz cd whisper-0.9.10 sudo python setup.py install #Installation de la Webapp cd /tmp/graphite/ wget https://launchpad.net/graphite/0.9/0.9.10/+download/graphite-web-0.9.10.tar.gz tar xzf graphite-web-0.9.10.tar.gz cd graphite-web-0.9.10 sudo python setup.py install #Configuration carbon cd /opt/graphite/bin sudo cp /opt/graphite/conf/carbon.conf.example /opt/graphite/conf/carbon.conf sudo cp /opt/graphite/conf/storage-schemas.conf.example /opt/graphite/conf/storage-schemas.conf #Lancement de Carbon sudo ./carbon-cache.py start #Configuration de la webapp sudo rm /etc/httpd/conf.d/wsgi.conf sudo cp /opt/graphite/examples/example-graphite-vhost.conf /etc/httpd/conf.d/vhost-graphite.conf sudo cp /opt/graphite/conf/graphite.wsgi.example /opt/graphite/conf/graphite.wsgi sudo cp /opt/graphite/webapp/graphite/local_settings.py.example /opt/graphite/webapp/graphite/local_settings.py cd /opt/graphite/webapp/graphite # Configuration de la base de données nécessaire pour la Webapp : sqlite par défaut. # Le script va créer la base de données et proposer de créer un compte utilisateur graphite sudo python manage.py syncdb # L’utilisateur apache doit pouvoir lire et écrire dans le répertoire de stockage sudo chown -R apache:apache /opt/graphite/storage/ # Lancement d’Apache sudo service httpd start
À ce stade, vous avez un processus carbon-cache.py qui écoute sur les ports 2003 et 2004 pour recevoir des métriques et une application web disponible à travers Apache, qui écoute sur le port 80 et accessible via navigateur. Il s’agit cependant de la configuration par défaut qui risque vite de se trouver limitée.
Configuration de Graphite
Si vous laissez fonctionner votre application quelques jours, vous allez rapidement vous rendre compte que la rétention des données par défaut est de 24h. Pour y remédier, il est nécessaire de réaliser quelques ajustements.
Stockage
La gestion du stockage est réalisée dans le fichier storage-schemas.conf et est composé d’un ensemble de bloc du type :
[title] pattern = <pattern-metric> retentions = <retentions_rule>
où :
- title : Un titre logique
- pattern : Il s’agit d’une expression régulière qui va être appliquée à chaque métrique et la première qui correspond sera utilisée. Les blocs sont lus dans l’ordre, du début du fichier jusqu’à la fin.
-
retentions : la règle de rétention à utiliser qui a la forme suivante
timePerPoint:timeToStore, timePerPoint:timeToStore, …
avec:
- timePerPoint : la durée d’un point (1sec, 1min, 10 min, 1h , etc …)
- timeToStore : le temps de rétention avec cette précision (1 journée, 1 semaine, etc …)
Quelques exemples
[mongodb] pattern = ^mongodb\. retentions = 1s:4h, 1m:6d, 1d:1y
Explications : Toutes les métriques qui commencent par “mongodb” vont être stockées de la façon suivante:
- 1 point par seconde pendant 4h
- 1 point par minute pendant 6 jours
- 1 point par jour pendant 1 an
Taille du fichier par métrique : 275Ko.
[default] pattern = .* retentions = 1s:1d, 1m:30d, 1h:1y
Explications : Pour toutes les métriques, stocker les données de la façon suivante :
- 1 point par seconde pendant un jour
- 1 point par minute pendant 1 mois
- 1 point par h pendant un an
Taille du fichier par métrique : 1,6Mo
Vous avez maintenant configuré Graphite avec la précision que vous souhaitez. Relancez le service carbon-cache.py et….rien ! En effet, ce fichier n’est lu que lorsqu’une métrique inconnue est reçue et qu’un nouveau fichier de données doit donc être créé. Les fichiers existants ne seront donc pas modifiés !
Dans ce cas vous avez deux solutions :
- Solution de facilité : Vous pouvez vous permettre de perdre les données existantes et il suffit de supprimer le répertoire de stockage (/opt/graphite/storage/whisper/ par défaut). Attention à un autre point cependant : par défaut et afin de limiter l’impact des créations de fichiers, Carbon va limiter le nombre de créations maximums de nouvelles métriques à 50 par minute. Ne vous inquiétez donc pas si certaines métriques n’apparaissent pas immédiatement (le processus-carbon-cache.py se monitor lui-même et il est donc possible de suivre le nombre de créations par minute directement dans Graphite)
-
Solution avec récupération des données : Whisper vient avec plusieurs outils de visualisation et de manipulation des données qui vont nous permettre de modifier la durée de rétention. Exemple d’utilisation pour une métrique bien précise :
sudo whisper-resize.py <link-to-wsp-file> 1s:4h 1m:6d 1d:1y
Il est bien sûr possible de faire des modifications en masse en scriptant un petit peu:
find /opt/graphite/storage/whisper/servers/ -name "*.wsp" -exec sudo whisper-resize.py --nobackup {} 1s:4h 1m:6d 1d:1y \;
Il est aussi possible d’afficher des informations sur un fichier de métriques afin de connaître la rétention utilisée :
whisper-info.py <nom-fichier-wsd>
Agrégation
L’agrégation se produit lorsque l’on change de zone de précision (eg : passage de 1 point par seconde à 1 point par minute).
Il est possible d’intervenir sur l’agrégation grâce au fichier facultatif storage-aggregation.conf dont le format ressemble à celui storage-schemas.conf. Il est composé de suites de blocs du type :
[title] pattern = <pattern-metric> xFilesFactor = <double> aggregationMethod = <average|max|min|sum|last>
Où :
- title: Un titre logique.
- pattern: Il s’agit d’une expression régulière qui va être appliquée à chaque métrique et la première qui correspond sera utilisée. Les blocs sont lus dans l’ordre, du début du fichier jusqu’à la fin.
- xFilesFactor: Ratio (entre 0 et 1) pour représenter le nombre de points nécessaires du palier précédent pour que la valeur soit non nulle. Cette valeur est utile lorsque le palier précédant n’est pas complet et qu’il manque des données. La valeur par défaut est 0.5.
- aggregationMethod: L’opération à appliquer pour agréger les données. La valeur par défaut est average.
Example :
[min] pattern = .*min$ xFilesFactor = 0.1 aggregationMethod = min
Explications : Lors de l’agrégation, pour que la valeur agrégée soit non nulle, il faut qu’il y ait au moins 10% des valeurs du palier précédant et la valeur minimum sera utilisée.
Comme pour le fichier storage-schemas.conf, la modification de ce fichier sera sans impact sur les métriques déjà créées. Il faut utiliser l’utilitaire whisper-resize.py avec les options –xFilesFactor et –aggregationMethod afin de modifier les options adéquates. À noter qu’il existe aussi l’utilitaire whisper-set-aggregation-method.py qui permet de modifier uniquement l’opération à appliquer sur les valeurs.
Whitelist/blacklist
Il est possible, au niveau du serveur Carbon, de gérer une liste de métriques acceptées ou au contraire rejetées. Bien entendu la configuration idéale est de ne pas envoyer de métriques inutiles, toutefois, il est parfois pratique de les exclure dans une configuration centralisée.
Afin d’activer la prise en charge des blacklist/whitelist, il faut tout d’abord ajouter une option dans le fichier de configuration carbon.conf :
USE_WHITELIST = true
Ensuite il faut créer les fichiers whitelist.conf et blacklist.conf dans le répertoire de configuration de Carbon (/opt/graphite/conf par défaut). Des fichiers d’exemples sont mis à disposition, il suffit de les renommer :
sudo cp /opt/graphite/conf/whitelist.conf.example /opt/graphite/conf/whitelist.conf sudo cp /opt/graphite/conf/blacklist.conf.example /opt/graphite/conf/blacklist.conf
La syntaxe de ces deux fichiers est assez simple. Ils consistent en une suite d’expressions régulières Python.
Si vous utilisez Diamond pour envoyer des métriques systèmes et que vous ne souhaitez pas avoir les détails de chaque CPU mais seulement le total, rien de plus simple. Il suffit de rajouter la ligne suivante dans blacklist.conf :
# Remove individual CPU details ^servers\..*\.cpu\.[a-z]+[0-9]+\..*
Ainsi les métriques du type ci-dessous seront ignorées
servers.<nom-serveur>.cpu.cpu[0-9].<metric>
Pour que les autres métriques soient acceptées, il faut qu’une ligne acceptant toutes les métriques soit ajoutée dans le fichier whitelist.conf :
#Accept all metrics \.
Il est fortement recommandé de commenter chaque ligne ajoutée à ces deux fichiers, la lecture des expressions régulières n’est pas forcément des plus aisée.
Un redémarrage du processus carbon-cache.py est nécessaire lorsqu’une option dans le fichier carbon.conf mais les modifications des fichiers whitelist.conf/blacklist.conf sont prises à chaud.
Attention également à ne pas ajouter de lignes vides dans le fichier blacklist.conf ! En effet, une ligne vide sera interprétée comme une expression régulière matchant tout et par conséquence toutes vos métriques seront ignorées !
Le fichier carbon.conf
Le fichier de configuration principal pour le processus carbon-cache.py est le fichier carbon.conf et il est divisé en trois parties distinctes :
[cache] #### # carbon-cache.py configuration #### [relay] #### # carbon-relay.py configuration #### [aggregator] #### # carbon-aggregator.py configuration ####
Dans notre installation mono-serveur avec uniquement un seul processus, les parties [relay] et [aggregator] sont tout simplement ignorées.
Le fichier par défaut est par ailleurs très bien auto documenté et permet principalement de définir les protocoles et les ports d’écoutes des différents processus.
Conclusion
Vous avez maintenant une installation Graphite installée et configurée parfaitement. Vous allez ajouter régulièrement de nouvelles métriques à grapher et vos tableaux de bord deviendront de plus en plus critiques: pour un web-commerçant qui suit son activité à la journée, comment se passer du nombre de ventes en temps (quasi) réel comparé à celui de la semaine précédente (si l’activité est très "journalisée") ?
La montée en charge et la haute disponibilité deviendront vite des pré requis indispensables à votre installation. Graphite permet de fonctionner dans un tel environnement, cela fera l’objet d’un second article.