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.