La supervision facile avec JMXTrans, collectd et Graphite

1 - Introduction

jmxUne des étapes d’une campagne de test de charge est de récupérer un certain nombre de métriques.
Plusieurs solutions sont possibles. L’une d’elles dans le monde Java, est d’utiliser JMX pour récupérer un certain nombre de métriques applicatives de la JVM, du serveur d’application, etc.
De nombreux outils permettent de faire cela, et nous allons nous focaliser sur  JMXTrans qui est puissant et simple à installer.
Afin de récupérer les statistiques systèmes (consommation processeur/mémoire, etc.) nous utiliserons collectd.
Enfin, pour afficher l'ensemble de ces métriques, nous utiliserons Graphite.

2 - Présentation des outils utilisés

2.1 - Présentation de JMXTrans

JMXTrans permet de récupérer les métriques de l’application cible à l’aide de JMX et de les transmettre à Graphite, StatsD, Ganglia, cacti/rrdtool, sortie standard et/ou l’écrire dans un fichier texte.

outil_jmxtrans_archi

JMXTrans a été développé pour être scalable, extensible et rapidement déployable.

Son installation consiste à décompresser un zip (ou sous Linux à installer un package), activer JMX et vérifier que tous les flux réseau sont ouverts entre les serveurs.

Plus d’informations sur le site officiel.

2.2 - Présentation de collectd

Collectd est une application qui va nous permettre de remonter les métriques systèmes vers Graphite et/ou un fichier csv.

Son architecture est basée sur des plugins qui permettent d’étendre collectd.

outil_jmxtrans_collectd_archi

Plus d’informations sur le site officiel.

2.3 - Présentation de Graphite

Graphite est un outil permettant de sauver des métriques et de les afficher sous forme graphique à la demande.

Il est composé de 3 parties :

  • une Webapp ;
  • un agent d’écoute nommé Carbon ;
  • un moteur de stockage nommé Whisper.

outil_jmxtrans_graphite_archi

Son installation est expliquée ici.

Après installation, il peut être judicieux de modifier le temps de rétention des métriques.

Pour cela il faut éditer le fichier storage-schemas.conf de Carbon.

[storage_name]
pattern = REGEXP PATTERN
retentions = fréquence:temps_de_retention,...

Par exemple pour PetClinic on pourrait avoir.

[PetClinic]
pattern = .*
retentions = 2s:5d,10m:1y

Dans cet exemple, un point de donnée représente deux secondes de mesure pendant les cinq premiers jours. Puis dix minutes l’année d’après.

Il faut faire attention lors du choix de ces valeurs, car il y a un risque sur le volume de données stocké par Whisper.

Une fois installé et lorsqu’on se connecte à la Webapp on se retrouve avec cet écran.

outil_jmxtrans_graphite_screen

De nombreuses possibilités pour l’affichage des courbes sont possibles.

Par exemple un certain nombre de fonctions pour le calcul des points sont sélectionnables.

outil_jmxtrans_fonction

Bien sûr le périmètre temporel du graphique peut être défini.

outil_jmxtrans_perimetre

Plus d’informations sur le site officiel.

3 - Configuration de la récupération des métriques à l’aide de collectd

La configuration et l’activation des plugins se fait dans le fichier collectd.conf.

Par exemple pour activer la sortie Graphite il faut éditer le fichier pour dé-commenter les lignes suivantes.

LoadPlugin write_graphite
 
		Host "localhost"
		Port "2003"
		Prefix "collectd"
		Postfix "collectd"
		StoreRates false
		AlwaysAppendDS false
		EscapeCharacter "_"

Ce qui nous donnera dans Graphite.

outil_jmxtrans_exemple_collectd

4 - Configuration de la récupération des métriques à l’aide de JMXTrans

La configuration de la récupération des metrics avec JMXTrans est assez simple et se fait à l’aide d’un fichier texte au format JSON.

4.1 - Théorie

Voila à quoi ressemble un fichier JSON pour JMXTrans.

{
  "servers" : [ {
    "host" : "localhost",
    "port" : "1105",
    "queries" : [ {
      "outputWriters" : [ {
        "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
        "settings" : {
          "outputFile" : "sortie.txt",
          "maxLogFileSize" : "10MB",
          "maxLogBackupFiles" : 200,
          "debug" : true,
          "typeNames" : ["name"]
        }
      } ],
      "obj" : "java.lang:type=Memory",
      "resultAlias": "Java",
      "attr" : [ "HeapMemoryUsage", "NonHeapMemoryUsage" ]
    } ]
  } ]
}

Ce fichier est découpé en plusieurs parties.

Partie 1 : On définit le serveur supervisé.

  "servers" : [ {
    "host" : "localhost",
    "port" : "1105",

 

Partie 2 : On déclare le bloque qui défini toutes les métriques que l’on va récupérer

    "queries" : [ {

 

Partie 3 : On définit où seront envoyées les métriques (ici un fichier texte)

      "outputWriters" : [ {
        "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
        "settings" : {
          "outputFile" : "sortie.txt",
          "maxLogFileSize" : "10MB",
          "maxLogBackupFiles" : 200,
          "debug" : true,
          "typeNames" : ["name"]
        }
      } ],

 

Partie 4 : On définit les métriques à récupérer

      "obj" : "java.lang:type=Memory",
      "resultAlias": "Java",
      "attr" : [ "HeapMemoryUsage", "NonHeapMemoryUsage" ]

 

Afin d’avoir le bon chemin pour la metric, on peut s’aider d’un outil graphique (VisualVM, JConsole...).

outil_jmxtrans_exemple_theorie

 

Afin de ne pas mettre les valeurs des paramètres en dur (port du serveur...), il est conseillé de :

  • remplacer les valeurs dans le fichier JSON par ${ma_variable}
  • de paramétrer les valeurs des variables à l’aide de JMXTRANS_OPTS

Par exemple.

  "servers" : [ { 
    "host" : "localhost", 
    "port" : "1105",

Devient

  "servers" : [ {
    "host" : "serveur_cible_host",
    "port" : "serveur_cible_port",

Et pour JMXTRANS_OPTS on a.

JMXTRANS_OPTS="-Dserveur_cible_host=localhost -Dserveur_cible_port=1105"

Dans les exemples suivants, on va utiliser l’application Spring PetClinic déployé sur un Apache Tomcat.

4.2 - Exemple 1 : Sortie Standard

Comme indiqué plus haut, pour modifier le type de sortie il suffit de modifier la partie outputWriters avec "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter".

Notre fichier JSON ressemblera à.

{
  "servers" : [ {
    "host" : "localhost",
    "port" : "1105",
    "queries" : [ {
      "outputWriters" : [ {
        "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter",
        "settings" : {
        }
      } ],
      "obj" : "java.lang:type=OperatingSystem",
      "resultAlias": "Operating_System",
      "attr" : [ "SystemLoadAverage", "AvailableProcessors", "TotalPhysicalMemorySize", 
      			"FreePhysicalMemorySize", "TotalSwapSpaceSize", "FreeSwapSpaceSize" ]
    } ]
  } ]
}

Voila l’équivalent avec VisualVM.
outil_jmxtrans_exemple_stdout

Le résultat sera.

~/Utils/jmxtrans-20121016-151320-36564abc7e$ Result [attributeName=SystemLoadAverage, className=com.sun.management.UnixOperatingSystem, typeName=type=OperatingSystem, values={SystemLoadAverage=0.21}, epoch=1355268801671] 
Result [attributeName=AvailableProcessors, className=com.sun.management.UnixOperatingSystem, typeName=type=OperatingSystem, values={AvailableProcessors=4}, epoch=1355268801671] 
Result [attributeName=TotalPhysicalMemorySize, className=com.sun.management.UnixOperatingSystem, typeName=type=OperatingSystem, values={TotalPhysicalMemorySize=4022161408}, epoch=1355268801671] 
Result [attributeName=FreePhysicalMemorySize, className=com.sun.management.UnixOperatingSystem, typeName=type=OperatingSystem, values={FreePhysicalMemorySize=749559808}, epoch=1355268801671] 
Result [attributeName=TotalSwapSpaceSize, className=com.sun.management.UnixOperatingSystem, typeName=type=OperatingSystem, values={TotalSwapSpaceSize=4170182656}, epoch=1355268801671] 
Result [attributeName=FreeSwapSpaceSize, className=com.sun.management.UnixOperatingSystem, typeName=type=OperatingSystem, values={FreeSwapSpaceSize=4170043392}, epoch=1355268801671]

4.3 - Exemple 2 : Fichier texte

Cette fois ci on va générer un fichier texte qu’on analysera avec QlikView.

{
  "servers" : [ {
    "host" : "localhost",
    "port" : "1105",
    "queries" : [ {
      "outputWriters" : [ {
        "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
        "settings" : {
          "outputFile" : "sortie.txt",
          "maxLogFileSize" : "10MB",
          "maxLogBackupFiles" : 200,
          "debug" : true,
          "typeNames" : ["name"]
        }
      } ],
      "obj" : "java.lang:type=Threading",
      "resultAlias": "Java",
      "attr" : [ "DaemonThreadCount", "PeakThreadCount", "ThreadCount", "TotalStartedThreadCount" ]
    } ]
  } ]
}

outil_jmxtrans_exemple_fichier

On remarque qu’on peut fixer la taille et le nombre de fichier de sortie afin qu’il y ait une rotation des fichiers.

Le résultat sera.

localhost_1105.Java.DaemonThreadCount	18	1355262287541
localhost_1105.Java.PeakThreadCount	20	1355262287541
localhost_1105.Java.ThreadCount	19	1355262287541
localhost_1105.Java.TotalStartedThreadCount	24	1355262287541
localhost_1105.Java.DaemonThreadCount	18	1355262347503
localhost_1105.Java.PeakThreadCount	20	1355262347503
localhost_1105.Java.ThreadCount	19	1355262347503
localhost_1105.Java.TotalStartedThreadCount	24	1355262347503

Dans QlikView, on utilisera le script de chargement suivant.

LOAD @1 as NameKPI_Complet,
	 subfield(@1, '.' ,1) as Server,
	 subfield(subfield(@1, '.' ,1),'_',1) as ServerName,
	 subfield(subfield(@1, '.' ,1),'_',2) as ServerPort,
	 subfield(@1, '.' ,2) as KPI_Category, 
 	 subfield(@1, '.' ,3) as NameKPI,
 	 subfield(@1, '.' ,2) & '.' & subfield(@1, '.' ,3) as KPI,
     @2 as Value_KPI, 
     @3,
timestamp(@3/ 86400000 + 25569) as TS,
date(floor(@3/ 86400000 + 25569)) as Date,
time(frac(@3/ 86400000 + 25569)) as Time
FROM
[yajug.txt]
(txt, codepage is 1252, no labels, delimiter is spaces, msq);

4.4 - Exemple 3 : Graphite

Si on veut de la supervision en temps réel de manière visuelle, Graphite est un bon candidat.

Dans notre premier exemple, on ne va plus superviser la JVM mais les connecteurs Tomcat (vous remarquerez l’utilisation de name=* afin d’inclure tous les connecteurs disponibles).

{
  "servers" : [ {
    "host" : "localhost",
    "port" : "1105",
    "queries" : [ {
      "outputWriters" : [ {
        "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter",
        "settings" : {
          "port" : 2003,
          "host" : "localhost"
        }
      } ],
      "obj" : "Catalina:type=ThreadPool,name=*",
      "resultAlias": "Tomcat_Connectors",
      "attr" : [ "currentThreadCount", "currentThreadsBusy" ]
    } ]
  } ]
}

outil_jmxtrans_exemple_graphite1

La sortie sous Graphite ressemblera à.

outil_jmxtrans_exemple_graphite1_screen

Cette fois ci on va superviser l’application Petlinic.

{
  "servers" : [ {
    "host" : "localhost",
    "port" : "1105",
    "queries" : [ {
      "outputWriters" : [ {
        "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter",
        "settings" : {
          "port" : 2003,
          "host" : "localhost"
        }
      } ],
      "obj" : "petclinic:type=CallMonitor",
      "resultAlias": "PetClinic",
      "attr" : [ "CallCount", "CallTime" ]
    } ],
    "numQueryThreads" : 2
  } ]
}

outil_jmxtrans_exemple_graphite2

outil_jmxtrans_exemple_graphite2_screen

5 - Mise en route de la supervision

Maintenant que tout est prêt, nous pouvons démarrer la supervision.

Dans un premier temps, démarrons Graphite.

Pour cela démarrons Carbon.

cd /opt/graphite/
./bin/carbon-cache.py start

Puis Apache afin d’avoir accès à l’interface web.
Sous Ubuntu, on peut le faire avec la commande suivante.

sudo service apache2 start

Maintenant c’est au tour de JMXTrans.

Avant de commencer, ne pas oublier d’activer JMX sur le serveur Apache Tomcat.

Pour cela il suffit d’ajouter au démarrage de la JVM de l’application cible les paramètres suivants.

 

Pour lancer JMXTrans, rien de plus simple.

./jmxtrans.sh start note_fichier_json

Plusieurs paramètres sont disponibles :

  • JSON_DIR : répertoires des fichiers json ;
  • LOG_DIR : répertoire de log ;
  • SECONDS_BETWEEN_RUNS : fréquence de récupération des métriques.

Une fois qu’on a plus besoin de la supervision, il suffit d’arrêter JMXTrans avec la ligne de commande suivante.

./jmxtrans.sh stop

Finissons avec collectd.

Sous Ubuntu.

sudo service collectd start

Les métriques remontées apparaîtront automatiquement dans l’interface web.

outil_jmxtrans_exemple_graphite2

outil_jmxtrans_graphite_screen2

6 - Conclusion

Lors d’une campagne de test de charge, il n’y a pas toujours le temps et/ou les moyens et/ou la possibilité d’installer une supervision. Dans ce cas la, le trio JMXTrans, collectd et Graphite permet de le faire rapidement et à moindre frais.

Sous Linux, l’installation peut se résumer à l’installation de packages et à la configuration quelques fichiers textes.

Cerise sur le gâteau, ces outils sont réputés scalables.

Pour aller encore plus vite ou si on n’a pas besoin de supervision temps réel, on peut se passer de Graphite et tout stocker dans des fichiers CSV pour une analyse après le tir.

Pour aller plus loin, on peut ajouter du Nagios/Cacti pour la gestion des alertes, partager facilement (avec de l’api de Graphite) les courbes de Graphite sur un wiki/site Internet.

2 réponses à to “La supervision facile avec JMXTrans, collectd et Graphite”

  • christophe:

    Merci pour ce blog que je trouve passionnant.

    J’ai une petite question au sujet des tests de charge. Qu’est ce que vous utilisez comme outil comparable à JMeter pour faire des tests de charge pour des WebSockets?

  • Alexandre:

    Merci beaucoup pour ce blog.

    Pour intégrer les info de Jmxtrans directement dans l’arborescence graphite d’une machine déjà existante :

    ‘rootPrefix’ : ‘collectdlocalhostcollectd’,

    dans votre fichier JSON jmxtrans.

    Alex.

Laisser un commentaire

Merci d'effectuer cette opération simple pour valider le commentaire *

Mots-clés
RSS Feed