Skip to content

Auslesen und verarbeiten von MBeans

by on September 14, 2017

Es gibt viele Möglichkeiten, die Leistung und den Status eines Java Applikations Clusters zu überwachen.
Aus historischen Gründen ist dabei JMX (Java Management Extensions) weit verbreitet.

Um diese Daten auslesen zu können, gibt es verschiedene Tools, die ich einmal kurz vorstellen möchte:

jmx4perl ist ein Befehlszeilenprogramm für einen einfachen Zugriff auf einen Anwendungsserver.
check_jmx4perl ist ein NRPE Plugin für die Überwachung von Java Anwendungen.
jmxdump ist ein Bestandteil der CoreMedia Toolsuite
jolokia ist ein REST Service, der einen erweiterten Zugriff auf die JMX Daten bietet.
jconsole / jmc sind grafische Frontends, welche direkt mit einem oder mehreren JMX Endpunkten verbunden sein können.
j4psh ist ein Frontend zu JMX::Jmx4Perl. Es bietet eine interaktive Shell für den Zugriff auf die JMX MBeans.

Ein Entwickler hat in der Regel jconsole oder das modernere jmc (Java Mission Control) im Einsatz, um einen Blick auf die jeweilige Applikation werfen zu können.

Um jmx4perl, check_jmx4perl oder j4psh nutzen zu können, muss man eine Reihe von Abhängigkeiten auflösen und sich ein umfangreiches Set an Perl Tools – unter Umständen auch direkt aus dem CPAN Repository – installieren.

Damit man die Tools in einer Testumgebung ausprobieren kann, nutze ich einen Docker Container, der diese Tools dafür sauber kapselt und mein Testsystem nicht unnötig ‘verseucht’.

Auch für jolokia steht mir ein Docker Container zur Verfügung.

j4psh ist eine Art Unix-Shell um durch die MBeans zu navigieren. Man kann damit sogar Aktionen – wie zum Beispiel das Auslösen des Garbage Collectors – durchführen.
Für ein Monitoring ist es aber nicht zu gebrauchen und wird daher nur kurz am Rande betrachtet.

Um MBeans zu lokalisieren, die man ggf. überwachen möchte, kann man das eingangs erwähnte jmc nutzen.

Damit steht einem ein einfacher grafischer Mechanismus für das Analysieren zur Verfügung. Wahrscheinlich funktioniert das ebenso mit j4psh, ist allerdings nicht so komfortabel.

Betrachten wir einmal die möglichen Tools näher

Zu diesem Zweck starte ich lokal auf meinem Testsystem einen jolokia Container. Dieser dient mir als Testumgebung und zum Auslesen der internen JMX Daten:

docker run \
  --rm --interactive --tty \
  --publish 8080:8080 \
  --publish 22222:22222 \
  --hostname jolokia \
  --name jolokia-default \
  bodsch/docker-jolokia:1707-30.1

Hierbei ist der Port 8080 das HTTP Rest-Interface von jolokia und der Port 22222 ist der RMI Port, um MBeans abfragen zu können.

Ein kurzer Test zeigt die Verfügbarkeit des jolokia Containers:

curl --silent http://localhost:8080/jolokia | json_reformat

{
  "request": {
    "type": "version"
  },
  "value": {
    "agent": "1.3.7",
    "protocol": "7.2",
    "config": {
      "maxCollectionSize": "0",
      "agentId": "172.17.0.2-7-156cde3c-servlet",
      "debug": "false",
      "agentType": "servlet",
      "serializeException": "false",
      "detectorOptions": "{}",
      "dispatcherClasses": "org.jolokia.jsr160.Jsr160RequestDispatcher",
      "maxDepth": "15",
      "discoveryEnabled": "false",
      "canonicalNaming": "true",
      "historyMaxEntries": "10",
      "includeStackTrace": "true",
      "maxObjects": "0",
      "debugMaxEntries": "100"
    },
    "info": {
      "product": "tomcat",
      "vendor": "Apache",
      "version": "8.5.16"
    }
  },
  "timestamp": 1504603653,
  "status": 200
}

Für die folgenden kleinen Tests nehme ich das Bean java.io,type=Memory und lese dieses mit jmx4perl, check_jmx4perl und direkt mit curl aus. Dabei messe ich mittels time die jeweilige Ausführungszeit.
Der jolokia Container dient mir hier als entsprechende Datenquelle. Das ganze ist natürlich auch mit jeder anderen Java Applikation möglich.

jmx4perl

time \
  docker run \
  --rm --name jmx4perl-default --interactive --tty \
  --link jolokia-default:jolokia bodsch/docker-jmx4perl:latest \
  jmx4perl http://jolokia:8080/jolokia read java.lang:type=Memory

    {
      HeapMemoryUsage => {
        committed => 241631232,
        init => 268435456,
        max => 1049034752,
        used => 97139144
      },
      NonHeapMemoryUsage => {
        committed => 31965184,
        init => 2555904,
        max => -1,
        used => 31005160
      },
      ObjectName => {
        objectName => 'java.lang:type=Memory'
      },
      ObjectPendingFinalizationCount => 0,
      Verbose => '[false]'
    }

real 0m0.958s
user 0m0.033s
sys 0m0.009s

Das Ergebnis ist ein Hash aus Objekten.
Um dieses Ergebnis weiterverarbeiten zu können, muss man sich einen eigenen Parser schreiben. Oder aber, man verwendet check_jmx4perl.

check_jmx4perl

check_jmx4perl ist ein ausgewiesenes Monitoring-Tool. Hierbei bekommt man als Ergebnis eine bereits vorformatierte Ausgabe. Es ist möglich, hier bereits Grenzwerte anzugeben.
Dadurch ist check_jmx4perl bereits für entsprechendes Monitoring wie Icinga in Version 1 und 2, Zabbix oder Nagios nutzbar.

time \
  docker run \
  --rm --name jmx4perl-default --interactive --tty \
  --link jolokia-default:jolokia bodsch/docker-jmx4perl:latest \
  check_jmx4perl --url http://jolokia:8080/jolokia --alias MEMORY_HEAP_USED

OK - [MEMORY_HEAP_USED] : Value 99286912 in range | [MEMORY_HEAP_USED]=99286912;;

real 0m1.042s
user 0m0.032s
sys 0m0.008s

Bei consol.de findet man weitere Beispiele, die relativ einfach adaptiert werden können.

Mit curl und ohne perl

Um JMX Messwerte auslesen zu können, benötigt man nicht unbedingt ein komplexes Perl Toolset.
Hier reicht ein relativ einfacher REST Service wie jolokia.

Der Vorteil dabei ist, dass man über HTTP kommuniziert, statt über die RMI Ports.
In großen Netzwerken mit entsprechenden Sicherheitsrichtinien sind solche Freigaben oft einfacher zu etablieren.

Zum Abfragen der Messpunkte schicken wir ein json an den jolokia Service:

time \
  curl --silent http://localhost:8080/jolokia \
  --data 
'{
  "type": "read",
  "mbean": "java.lang:type=Memory",
  "attribute": "HeapMemoryUsage",
  "target": { "url": "service:jmx:rmi:///jndi/rmi://localhost:22222/jmxrmi" }
}' | jq '.value'

{
  "init": 268435456,
  "committed": 241631232,
  "max": 1049034752,
  "used": 130072400
}

real 0m0.011s
user 0m0.006s
sys 0m0.003s

Als Ergebnis erhalten wir wiederum ein json, was wir einfach mit entsprechenden Tools parsen und weiterverwenden können.

Auch mehrere MBeans lassen sich über sogenannte Bulk-Checks auslesen.

Damit kann man eine Reihe von Checks bequem in einen Request zusammenfassen und diese gemeinsam auswerten:

time \
  curl --silent http://localhost:8080/jolokia \
  --data 
'[{
  "type": "read",
  "mbean": "java.lang:type=Memory",
  "attribute": "HeapMemoryUsage",
  "target": { "url": "service:jmx:rmi:///jndi/rmi://localhost:22222/jmxrmi" }
},
{
  "type": "read",
  "mbean": "java.lang:type=Runtime",
  "attribute": "Uptime",
  "target": { "url": "service:jmx:rmi:///jndi/rmi://localhost:22222/jmxrmi" }
}]' | jq '.[].value'

{
  "init": 268435456,
  "committed": 241631232,
  "max": 1049034752,
  "used": 153696648
}
9615405

real 0m0.031s
user 0m0.014s
sys 0m0.005s

Des weiteren ist der Einsatz eines Asterisk (*) möglich, so dass man auch größere Ergebnismengen erhalten kann:

time \
  curl --silent http://localhost:8080/jolokia \
  --data 
'{
  "type": "read",
  "mbean": "java.lang:type=*",
  "attribute": "HeapMemoryUsage",
  "target": { "url": "service:jmx:rmi:///jndi/rmi://localhost:22222/jmxrmi" }
}' | jq '.value'

{
  "java.lang:type=Memory": {
    "HeapMemoryUsage": {
      "init": 268435456,
      "committed": 241631232,
      "max": 1049034752,
      "used": 134367800
    }
  }
}

real 0m0.044s
user 0m0.012s
sys 0m0.006s

 

From → Tips & Tricks

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s