© Excellent backgrounds/Shutterstock.com
Teil 4: Java EE Microservices überwachen

Anwendungen röntgen


Autos informieren den Fahrer über Geschwindigkeit, Drehzahl, Tankanzeige, Temperatur und manchmal auch über Ladedruck oder das aktuelle Drehmoment des Motors. Außerdem verfügen alle modernen Fahrzeuge über eine Diagnoseschnittstelle. Espressomaschinen zeigen Druck und Temperatur des Kessels an. Sogar Rasierer messen die Zeit und informieren den Benutzer über bevorstehenden Klingenwechsel. Komplexe Enterprise-Anwendungen dagegen werden meistens ohne jegliches Monitoring betrieben. Das soll bei unserer Microservices-Anwendung mit Java EE nicht der Fall sein.

Alle Monitoring- und Diagnostik-Use-Cases und -User-Stories werden in der Entwicklung bewusst ignoriert. Man verlässt sich lieber auf die in Produktion installierte Monitoring- und Diagnostiksoftware und hofft, dass man ohne jegliche Entwicklungsaufwände hilfreiche Information aus der Software nachträglich extrahieren kann. Die JVM sieht die Installation von Agenten vor [1]. Diese haben direkten Zugriff auf den Bytecode während der Ausführung und werden oft von den Monitoringsystemen verwendet. Andere Performancemonitoring- und Diagnostiksysteme basieren auf Bytecodemanipulationen und dekorieren so die relevanten Methoden. Man betrachtet das Monitoring als ein Cross-Cutting Concern [2] und versucht mit Methoden der aspektorientierten Programmierung (AOP) [3], wertvolle Informationen nachträglich zu erhalten: Eine Benutzeranfrage kann auf dem Server von dem Parsing des HTTP Requests bis zur Kommunikation mit der Datenbank überwacht werden. So lassen sich Statistiken über SQL-Statements, Threads, Performance, Speicherbedarf, Flaschenhälse und die am häufigsten aufgerufenen Methoden sammeln. Man erhält eine transaktionale Sicht auf das System und versucht, wichtige Use Cases nachträglich hoffentlich sinnvoll benannten Methoden zuzuordnen. Diese Strategie übertragen auf PKWs bedeutet: Moderne PKWs würde man ohne Geschwindigkeitsanzeige oder Drehzahlmesser ausliefern und sich dann auf das bereits existierende GPS-Satellitensystem und Ultraschall verlassen.

Vergessene Fähigkeiten

Was viele vergessen: Ein Applikationsserver verfügt bereits über detailliertes Wissen über die Vorgänge in den deployten Komponenten. Denn Applikationsserver verwalten den Lebenszyklus von Servlets, EJBs sowie CDI-Komponenten und sind für das Pooling von JDBC Connections und Threads zuständig. Sicherheit, Nebenläufigkeit und Transaktionalität werden bereits intern mit AOP-Mitteln implementiert. Ein Applikationsserver nutzt die Dependency Injection für die Dekoration von Komponenten mit standardisierten Querschnittsaspekten. So werden beispielsweise für jede mit @Stateless annotierte Klasse Transaktions-, Sicherheits- und Nebenläufigkeitsaspekte installiert.

Seit Dezember 2001 implementieren alle Java-EE-Applikationsserver den JSR 77 „J2EE Management Spezifikation“ [4]. So realisieren alle deployten Komponenten des Applikationsservers das spezifische J2EE­Man­aged­Object (z. B. StatelessSessionBean) und veröffentlichen auch eine Reihe von im Paket javax.management.j2ee.statistics (TimeStatistic, RangeStatistic, Bound­ary­Sta­tis­tic, CountStatistic) standardisierten Statistiken. Allerdings bleibt jedem Hersteller freigestellt, über welches Protokoll er die Statistiken der Außenwelt zur Verfügung stellt. Von der Kommandozeile über JMX zu REST-Schnittstellen – der Weg zu den Schnittstellen ist leider nicht standardisiert.

Den Taschenrechner überwachen

Während des Deployments werden die Klassen einer Java-EE-Anwendung von dem Applikationsserver analysiert und mit Zusatzfähigkeit wie Persistenz, Transaktionen, Lebenszyklus, aber auch Monitoring versehen, z. B. Singleton, Request, HTTP-Session. Aufgrund der Deploy-Zeit-Analyse erhält ein Applikationsserver eine Röntgensicht auf den Microservice. So werden nicht nur die JAX-RS-Ressourcen, sondern auch für alle injizierten POJOs Statistiken gepflegt.

Was heißt das für unsere Taschenrechneranwendung? Unser Addition-Miniservice besteht aus einer JAX-RS-Ressource (AdditionResource) und einer Facade (Addition). Die AdditionResource ist eine JAX-RS Resource Class, also ein POJO, das lediglich mit der @Path-Annotation versehen ist:

@Path("addition") public class AdditionResource {}

Die AdditionResource wird für jeden Request neu erzeugt und von dem Applikationsserver als ein einfacher POJO behandelt. Für JAX-RS-Resource-Klassen werden keine Statistiken erfasst. Beim GlassFish-Applikationsserver [5] oder dem besser gepflegten Fork Payara [6] stehen alle Monitoringstatistiken via REST-Schnittstelle bereit [7]. Die Monitoringfähigkeiten lassen sich sowohl über die CLI, Admin Console als auch die REST-Management-Schnittstelle veröffentlichen.

Den Einstieg zu den Statistiken eines Microservice erhält man über den REST-URI: http://localhost:4848/­monitoring/domain/server/applications/[WAR_NAME]. Der Applikationsserver antwortet auf die GET-Anfrage http://localhost:4848/monitoring/­domain/­server/­applications/­addition.json mit Folgendem:

{ "message": "", "command": "Monitoring Data", "exit_code": "SUCCESS", "extraProperties": { "entity": {}, "childResources": { "Addition": "http:\/\/localhost:4848\/monitoring\/domain\/server\/applications\/addition\/Addition", "server": "http:\/\/localhost:4848\/monitoring\/domain\/server\/applications\/addition\/server" } } }

Der Schlüssel childResources.Addition repräsentiert die Addition Stateless EJB (Listing 1).

Listing 1

@Stateless public class Addition { public int add(int a, int b) { int result = a + b; if (result == 42) { thinkLonger(); } return result; } void thinkLonger() { try { Thread.sleep(1000); } catch (InterruptedException ex) { Logger.getLogger(Addition.class.getName()).log(Level.SEVERE, null, ex); } } }

Wie erwartet, fehlen die Statistiken für die Addi­tion­Resource. Allerdings wird mit dem Hinzufügen der @ State­less-Annotation nicht nur das Monitoring von AdditionResource aktiviert, sondern auch noch die Performance messbar verbessert. Die AdditionResource wird nun nur noch einmal pro parallelem Thread und nicht mehr bei jedem Zugriff erzeugt. Eine erneute Ausführung des Requests liefert kündigt die Statistiken beider Klassen:

"childResources": { "Addition": "http:\/\/localhost:4848\/monitoring\/domain\/server\/applications\/addition\/Addition", "AdditionResource": "http:\/\/localhost:4848\/monitoring\/domain\/server\/applications\/addition\/AdditionResource", "server": "http:\/\/localhost:4848\/monitoring\/domain\/server\/applications\/addition\/server" }

Der AdditionResourceIT-Systemtest wird einmalig ausgeführt (mvn failsafe:integration-test) (Listing 2).

Listing 2

public class AdditionResourceIT { private Client client; private WebTarget tut; static fin...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang