Home monitoringlove #1 – java Applikationen (update)
Post
Cancel

monitoringlove #1 – java Applikationen (update)

Dieser Beitrag wurde vor mehr als 7 Jahren veröffentlicht!
Höchstwahrscheinlich ist dieser inzwischen veraltet.

Okay, der Artikel greift massiv vorweg, ist aber schneller zusammen geschrieben! :)

Ich möchte hier die unterschiedlichen Möglichkeiten des Monitorings von Applikationen beschreiben.

Wobei mein Schwerpunkt auf Tomcat und Java liegen wird.

Das ganze habe ich auch in ein (spezialisiertes) puppet-Modul einfließen lassen, was man sich bei github ansehen und forken kann. Über Pull-Request oder Anregen freue ich mich natürlich ebenso!

Überwachen von PHP Applikationen

Was bei „billigen“ Applikationen auf PHP-Basis mit einem simplen GET-Request machbar ist, wird bei „richtigen“ Applikationen in einem Container (sei es JBoss, fireFly oder Tomcat) etwas komplexer. Bei PHP-Applikationen bieten die Entwickler manchmal eine HealthCheck-URI an, welche den Zustandes der Applikation während der Aufrufes repräsentieren soll. Vieles kommt dann über Symfony (weil das eh schon da ist und weil „einfach“ ja nie „schlank“ bedeutet) und testet Verbindungen zur Datenbank und andere Endpunkte.
Netter Versuch, aber nicht wirklich optimal.
(Ich wünsche mir ja schon seit Jahren so etwas wie einen ‚Tomcat‘ für PHP … aber das ist eine andere Geschichte)

Überwachen von Java Containern

Bei einem Applikationscontainer wie Tomcat (als Beispiel) kann man sich alle möglichen Parameter per JMX ausgeben lassen. Leider ist JMX nicht wirklich einfach menschenfreundlich und auch eine Abfrage gestaltet sich hier etwas schieriger. Etwas schnelles und simples in Bash ist nicht „mal eben schnell“ hingezaubert. Perl nutze ich viel zu selten um da richtig fit zu sein und zu Python hat jeder seine eigene Meinung. (Ja, Ruby steht mit Absicht nicht in der Aufzählung!)

Jolokia

Bei meinem letzten Projekt bekamen wir eine massiv große Anzahl von Java-Applikationen in einem Tomcat-Container. Mit der bis dato etablierten Monitoringlösung wäre die Überwachung der ganzen Services völlig ausgeartet bzw. nicht möglich. Aus dem Grunde implementierte ich eine Icinga2 Monitoring-Node und stürzte mich auf das Sammeln von Informationen. Beim Thema JMX empfahl mir ein extern hinzugezogener Spezialist jolokia.

Jolokia ist eine eigenständige kleine Java-Application ohne externe Abhängigkeiten, welche mir einen einfachen Zugriff auf die JMX Parameter eines (oder mehrerer) Tomcats ermöglicht. Dazu schickt man in einem POST-Request seine Anfragen an den Zieltomcat und erhält als Ergebniss eine lesbare Ausgabe im json Format.

1
2
3
4
5
curl \
  --silent \
  --request POST \
  --data "$(cat /var/cache/monitor/tc_memory.post)" http://localhost:8080/jolokia/ | \
  python -mjson.tool > /var/cache/monitor/tc_memory.result

Das entsprechende POST-File:

1
2
3
4
5
6
cat /var/cache/monitor/tc_memory.post
{
  "type" : "read",
  "mbean" : "java.lang:type=Memory",
  "target" : { "url" : "service:jmx:rmi:///jndi/rmi://localhost:9090/jmxrmi", }
}

Ich habe mir angewöhnt, für das Monitoring einen eigenen Tomcat zu installieren und die jolokia Applikation dann gezielt gegen die die überwachenden System laufen zu lassen. Da das ganze mit der Zeit einen größeren Umfang erreicht hat und ich von Natur aus faul genug bin, möchte ich wiederkehrende Dinge nur einmal erledigen, also habe ich mir entsprechende Templates gebaut, welche auf dem Zielsystem mit dem Port des zu überwachenden Tomcats versehen werden. Mit der Zeit wuchs dann auch die Anzahl der zu überwachenden Parameter, weshalb ich mir einen Weg überlegen musste, um entsprechenden Templates möglichst automatisch auszurollen und aus den POST-Files meine Results zu bekommen. Das Ausrollen der Templates übernimmt bei mir mitterweile ein entsprechendes puppet-Modul.

Generieren der POST-Files

Für das parsen und das generieren der POST-Files muss ich etwas tiefer in die Tasche greifen. Mein Script soll halbwegs intelligent sein. D.h. selbst herausfinden, welche Tomcat-Instanzen es überwachen soll.

Liste von laufenden Applikationen

Da der JMX Port für meine Anforderung immer Verfügbar sein muss, ist das mein Indikator für eine laufender Tomcat-Instanz. Das ganze kommt dann in eine simple bash-funktion zur Geltung:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
getRunningApplications() {
  # alle Prozesse, die was mit Java tu tun haben, ausser unserem Monitoring-Tomcat
  PIDS="$(ps -eopid,user,command | \
    grep java | \
    grep -v grep | \
    grep -v monitor-tomcat | \
    awk -F ' ' '{print $1}')"

  for pid in ${PIDS}
  do
    # Der Port xx099 ist bei einer Tomcat-WebApp immer vorhanden
    port="$(lsof -i | \
      grep 099 | \
      grep LISTEN | \
      grep ${pid} | \
      awk -F ':' '{print $2}' | \
      awk -F ' ' '{print $1}')"
    PORTS="${PORTS} ${port}"
  done
}

Diese Funktion sammelt mir alle xx099er Ports der laufenden Tomcat Applikationen ein.

Mit dieser Liste können wir dann weiter arbeiten.

Erstellen der POST-Files

Jeder Tomcat bietet eine Menge an JMX-Checks. Und wir benötigen eine Auswahl davon. Also legen wir uns zu Beginn ein kleine Auswahl zurecht:

1
standardJMX="TomcatThreadPool Threading Service Memory ClassLoading GarbageCollector"

Diese können wir dann ggf. erweitern:

1
2
JMX_20099="${standardJMX} foo"
JMX_21099="${standardJMX} foo bar"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
for p in ${PORTS}
  do
    echo "port: ${p}"
    jmx=JMX_${p}
    echo ${!jmx}

    for c in ${!jmx}
    do
      echo "check: ${c}"

      file_tpl="${TEMPLATE_DIR}/${c}.json.tpl"

      dir="${TMP_DIR}/${p}"
      [ -d ${dir} ] || mkdir -p ${dir}

      file_dst="${dir}/${c}.json"

      if [ -f "${file_tpl}" ]
      then
        [ -f ${file_dst} ] && continue
        sed -e "s/%PORT%/${p}/g" ${file_tpl} > ${file_dst}
      fi
    done
  done

Damit erzeugen wir aus unseren vorgefertigen Template-Dateien nutzbare POST-Files, die wir an unseren Monitoring Tomcat schicken können.

results erzeugen

Der Rest ist dann relativ einfach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for p in ${PORTS}
  do
    dir="${TMP_DIR}/${p}"
    for i in $(ls -1 ${dir}/*.json)
    do
      dst="$(echo ${i} | sed 's/\.json/\.result/g')"
      tmp="$(echo ${i} | sed 's/\.json/\.tmp/g')"
      touch ${tmp}
      ionice -c2 nice -n19 \
          curl \
            --silent \
            --request POST \
            --data "$(cat $i)" http://localhost:8080/jolokia/ | \
            python -mjson.tool > ${tmp}

      [ $(stat -c %s ${tmp}) -gt 0 ] && {
        mv ${tmp} ${dst}
      }
    done
  done

Wir nutzen wieder unsere PORT-Liste und suchen in dem jeweiligen Verzeichnis nach unseren POST-Files, die wir dann nacheinander an den Monitoring-Tomcat schicken. Damit wir immer ein valides Ergebnis haben, gehen wir noch den Umweg über eine temporäre Datei.

Fazit

Das Monitoring von Tomcats ist einfach, wenn man sich ein wenig mit der Materie auseinander setzt. Und jolokia hat mir das ganze Thema deutlich vereinfacht.

Das ganze obige Beispiel ist ziemlich I/O lastig! Hier lohnt sich der Einsatz eines tmpfs.

This post is licensed under CC BY 4.0 by the author.