Teil 6: Java EE und Microservices mit einem Dashboard überwachen
Teil 6: Java EE und Microservices mit einem Dashboard überwachen
Ein beobachtbarer Microservice muss genügend Information für die externe Bestimmung seines Zustands (Health) veröffentlichen. Die Fähigkeit, die notwendigen Daten zu veröffentlichen, wird zu einer nicht funktionalen Eigenschaft des Systems. Java EE bringt von Haus aus viele Funktionalitäten mit, da ist etwas Langeweile schon fast vorprogrammiert.
Im „Embrace Boredom“-Post [1] wird vorgeschlagen, auf möglichst langweilige Technologien zu setzen und jeweils erst nach dem Erreichen einer bestimmten Reife Neues auszuprobieren. Solche Experimente sollten die Ausnahme und nicht die Regel sein. Dabei sind langweilige Technologien keinesfalls schlecht, gelten als bereits etabliert, ohne Überraschungen, zeigen bekanntes Verhalten und möglichst viele Antworten auf Stack Overflow. Java-EE-Applikationsserver sind langweilig. Sie können als das Betriebssystem für die Fachlichkeit angesehen werden. Der Anwendungscode ist klar und strikt von der Laufzeitumgebung getrennt. Diese strikte Trennung ist besonders in Docker- und Cloud-Umgebungen vorteilhaft, in denen das Thin WAR (die Anwendung) und der Java-EE-Server sogar binär durch aufeinander aufbauende Layer separiert sind.
Applikationsserver sind gut observierbar. Von dem HTTP Stack über Transaktionen bis zu Data Sources veröffentlichen alle Subsysteme fleißig Metriken, und das seit über fünfzehn Jahren. Die Metriken werden mehr oder weniger bunt visualisiert. Grafische Darstellung und nachträgliche Auswertung der Metriken sind eindeutig die Schwäche der meisten Applikationsserver.
Die JAX-RS-Ressource PingResource wurde mit großem Vertrauen bezüglich der Performance der Java-EE-Applikationsserver implementiert:
@Path("ping")
public class PingResource {
@GET
public void ping(@Suspended AsyncResponse response) {
response.setTimeout(1, TimeUnit.NANOSECONDS);
response.resume("Java EE 8 is crazy fast");
}
Der Timeout wurde mit einer Nanosekunde konfiguriert, was den 503-HTTP-Status verursachen sollte. Die Abfrage: curl -i http://localhost:8080/problematic/resources/ping liefert tatsächlich
HTTP/1.1 503 Service Unavailable
Server: Payara Server 4.1.2.173 #badassfish
(…)
Eine 503-Antwort verursacht durch ein Timeout innerhalb der JAX-RS-Ressource sagt viel über den Zustand des Microservice aus und sollte festgehalten werden. Der Payara-Server führt Statistiken über alle HTTP-Statuscodes aus. Diese Monitoringfähigkeit ist keineswegs neu und steht bereits seit GlassFish v3 und etwa acht Jahren über JSON, XML und HTML zur Verfügung. Für die Abfrage der Anzahl der 503-Statuscodes ist folgender curl-Aufruf ausreichend: curl -i http://localhost:4848/monitoring/domain/server/http-service/server/request/count503.json, der mit
{"message":"","command":"Monitoring Data","exit_code":"SUCCESS","extraProperties":{"entity":{"count503":{"unit":"count","lastsampletime":1511298198933,"name":"Count503","count":1,"description":"Number of responses with a status code equal to 503","starttime":1511298187373}},"childResources":{}}}
beantwortet wird. Die interessante Information ist der Inhalt des Keys count, in unserem Fall 503.
Der Applikationsserver veröffentlicht jede Menge Metriken, meist ohne bunte Dashboards. Das ist auch gut so, da gute Open-Source-Tools nicht nur die Visualisierung, sondern auch die Auswertung und das Alerting bereitstellen können. Prometheus [2] steht in Version 2 zur Verfügung, ist bewährt, einfach zu installieren und somit per Definition mindestens so langweilig wie Java EE selbst. Prometheus holt sich periodisch Metriken ab und speichert sie effizient in einer internen Zeitreihendatenbank ab. Alle gespeicherten Metriken liegen für eine nachträgliche Auswertung bereit. Für Auswertungen steht eine eigene Abfragesprache PromQL zur Verfügung. Allerdings konsumiert Prometheus ausschließlich Metriken in eigenem Textformat. Die Prometheus-Metriken sind unter dem URI: http://localhost:9090/metrics einsehbar und sehen so aus:
(…)
http_request_duration_microseconds 859
Die einzelnen mit Unterstrich getrennten Segmente haben semantische Bedeutung und entsprechen den Best Practices in Prometheus: componentprefix_metric_unit_suffix. Der Suffix wird als Beschreibung der Einheit verwendet. Die Unit ist die Einheit selbst (z. B. duration), die metric ist selbsterklärend und der componentprefix entspricht dem Namen des Microservice oder einer Komponente. Leider sind die Payara-REST/JSON-Metriken nicht mit Prometheus kompatibel. Auch andere Nicht-Java-Dienste veröffentlichen ihre Metriken über Exporter, die die Konvertierung übernehmen. Da wir keinen Einfluss auf das Format der Metriken des Applikationsservers haben, müssen wir das JSON-Format ins Prometheus-Underscore-Separated-Values-Format überführen.
Die Konvertierung der Formate kann ...