23 VIEWS

Vorstellung: Java Flight Recorder

05.07.2021

Java kann fast so schön wie Fliegen sein. Dank dem Java Flight Recorder und dem Java Mission Control können spannende Daten über den Flug einer Java Anwendung gesammelt werden.

Anwendungen verstehen und nachvollziehen zu können, ist beim Einsatz und der Entwicklung von Software ein wichtiger Aspekt. Neben den bestehenden Lösungen zum Logging, Monitoring und Debugging gibt es mit dem Java Flight Recorder einen frischen "Player", der in dem Java Ökosystem an Relevanz zu gewinnen scheint. Daher soll dieser Artikel eine grundlegende Übersicht über das JVM Werkzeug schaffen.

Der Java Flight Recorder

JFR steht für Java Flight Recorder. Dahinter verbergen sich Werkzeuge zum analysieren und besser verstehen von Java Anwendungen. JFR ist ein Bestandteil des JDKs und scheint unter anderem durch den Wechsel von einer kommerziellen Lizenz zu einer offeneren Lizenz relevanter mit aktuellen Java Versionen zu werden.

Das Prinzip hinter dem Werkzeug kann, wie der Name schon verrät, mit einem Flugschreiber verglichen werden. Eine Java Anwendung produziert dabei Events, welche dann bei Bedarf aufgezeichnet und ausgewertet werden können. Gegenüber klassischen Logging und Metrikenframeworks liegt die Besonderheit tatsächlich darin, Events gezielt über einen Zeitraum aufzeichnen zu können. Das Ergebnis ist eine Datei, die mit der Desktopanwendung Java Mission Control ausgewertet werden kann. Der Weg über die Datei hat den Vorteil, dass man eine Aufzeichnung starten kann und es dann nicht notwendig ist, während der Aufzeichnung eine bestehende Verbindung aufrechtzuhalten.

Die GraalVM hat seit Kurzem auch eine Unterstützung für den Java Flight Recorder.

JFR lebt von Events

Grundlegend ist das Konzept der Events. Events beinhalten nicht nur Domain spezifische Informationen über das Geschehnis, sondern bilden immer auch Metriken, wie z.B. den Zeitpunkt des Auftretens und die Dauer ab. Generell werden folgende drei Eventtypen unterschieden:

  • Instant Events werden direkt beim Auftreten erfasst
  • Duration Events bilden eine Zeitspanne ab und werden entsprechend erst beim Abschluss erfasst
  • Sample Events erfassen mit einer Regelmäßigkeit einen bestimmten Zustand

Neben vielen vordefinierten Events aus dem JDK kann man beliebige eigene Events definieren. Dazu erstellt man für jedes Event eine Klasse, die man von jdk.jfr.Event ableitet. Über Annotationen kann man dann Metainformationen, wie z.B. einen Namen oder eine Beschreibung, ergänzen. Über entsprechend annotierte Felder werden die möglichen Daten des Events definiert.

Hier ein Beispiel, wie solch ein Event definiert werden könnte, wenn z.B. ein User eine Datei von einem Server herunterlädt.

Dank der Ableitung von jdk.jfr.Event kann man das Event wie ein Pojo verwenden. Das heißt man erzeugt über new eine Instanz des Events und erfasst es abschließend mit einem Aufruf der commit() Methode. Die Api ist aber noch ein wenig komplexer, um besonders effektiv und gezielt Events erfassen zu können.

  • event.isEnabled() ermöglicht es, relevanten Code (z.B. das Sammeln von Daten für das Event) nur dann auszuführen, wenn das Event überhaupt gefragt ist.
  • Über event.begin(); und event.end(); kann man die Zeitspanne von Duration Events messen.
  • event.shouldCommit() hat eine ähnliche Aufgabe wie event.isEnabled(). Es kann zwar sein, dass ein Event aktiv ist, aber nur dann erfasst werden soll, wenn es eine gewisse Zeitspanne überschreitet (z.B. zum Erfassen von besonders langsamen Abfragen).

Das folgende Beispiel veranschaulicht, wie die vorgestellten Methoden in Kombination eingesetzt werden können.

Events aufzeichnen und auswerten

Damit unsere Anwendung auftretende Events aufzeichnet, müssen wir den Flight Recorder starten. Dazu gibt es die folgenden Möglichkeiten.

Möglichkeit A: JVM Parameter beim Starten der Anwendung

  • delay gibt an, wie lange der Start des Flight Recorders nach dem Start der Anwendung verzögert werden soll.
  • duration gibt an, wie lange der Flight Recorder aufzeichnen soll.
  • name gibt der Aufzeichnung einen Namen, der später hilfreich sein kann, verschiedene Aufzeichnungen zu unterscheiden.
  • filename gibt an, wie die Datei mit den Aufzeichnungen heißen soll. Die Datei wird im Verzeichnis angelegt, in dem der Prozess gestartet wird. Diese Datei beinhaltet nach dem Ausführen des Flight Recorders die aufgezeichneten Events.
  • settings wählt ein Template aus, das Voreinstellungen (Filterung der Events) für verschiedene Szenarien vorgibt. Die Templates werden aus dem $JAVA_HOME/lib/jfr Verzeichnis gespeist. Hinter dem Template "default" steht zum Beispiel entsprechend die Datei "default.jfc". Die Template Daten lassen sich entweder direkt im XML Format in der Textdatei editieren oder man kann auf die Java Mission Control Oberfläche zurückgreifen, welche einen umfangreichen Editor bereitstellt.

Da man schon beim Starten definieren muss, was aufgezeichnet werden soll, ist diese Variante eher für kurze Ausführungszyklen wie z.B. beim Entwickeln und Testen geeignet und eher nicht für einen langlaufenden Server.

Möglichkeit B: Flight Recorder über jcmd starten

jcmd ist ein Kommandozeilen Tool, das mit diversen JDK Distributionen mitgeliefert wird. Es erlaubt das Ausführen von Befehlen für in einer JVM laufende Prozesse.

Als Erstes muss die Id des Java Prozesses herausgefunden werden, indem wir den Flight Recorder starten wollen. Dazu rufen wir jcmd einfach ohne Parameter auf.

In der ersten Spalte sehen wir die gesuchte Id.

Jetzt können wir über jcmd verschiedene JFR Befehle für unseren Prozess ausführen. Das Pattern dafür ist jcmd <pid|MainClass> <command> [parameters].

Mögliche Befehle (command) sind:

  • JFR.start
  • JFR.check
  • JFR.stop
  • JFR.dump

Eine Referenz zu den Befehlen kann man auf der Oracle Webseite finden oder sich durch das Pattern jcmd <pid|MainClass> help <command> ausgeben lassen.

Hier z.B. die Ausgabe für den JFR.start Befehl:

Diese Variante ermöglicht es, eine Ad-hoc Aufzeichnung zu starten. Das funktioniert vor allem dann, wenn man eine Terminalverbindung auf den Rechner mit der zu überwachenden Java Anwendung hat. Voraussetzung ist natürlich auch, dass das jcmd Programm auf dem entsprechenden System vorhanden ist.

Möglichkeit C: Java Mission Control verwenden

Das Java Mission Control (kurz: JMC) ist eine grafische Oberfläche für den Java Flight Recorder (kurz: JFR). Heruntergeladen werden kann das Programm zum Beispiel hier: https://adoptopenjdk.net/jmc.html

Da es sich um eine Eclipse Anwendung handelt, kann man das Programm auch als Erweiterung in Eclipse installieren. Dazu findet man unten auf der Download Seite entsprechende Archive, die man in Eclipse über Help > Install New Software... auswählen kann.

Das JMC erlaubt es, die oben aufgeführten Aktionen wie das Starten einer Aufnahme bequem aus einer Übersicht heraus auszuführen. Erst über die Oberfläche bekommt man eine gute Übersicht über die Möglichkeiten, den JFR zu steuern. So kann man zum Beispiel Bedingungen definieren, ab welchen Schwellenwerten eine volle Aufzeichnung gestartet werden soll, um so Randfälle ohne zu viel Overhead einfangen zu können.

Darüber hinaus ist das JMC die erste Wahl, wenn es darum geht, Aufzeichnungen, die mit dem JFR gemacht wurden, auszuwerten. Wie man es von anderen Desktopanwendungen gewohnt ist, wählt man über File > Open File... die Aufzeichnungsdatei (*.jfr) aus.

JMC Event Explorer
Abb. 1: JMC Event Explorer, Quelle: Eigene Darstellung (Screenshot)

Wie im Screenshot oben zu sehen, findet man hier je nach Aufzeichnung jede Menge JVM spezifische Metriken. Im Event Browser findet man auch die weiter oben selbst definierten Events wieder.

Möglichkeit D: JFR Event Streaming

In dem bisher beschriebenen Prinzip hinter dem Java Flight Recorder steckt der Nachteil, dass zwischen Aufzeichnung und Auswertung immer ein wenig Zeit liegt. Man kann also immer nur einen statischen Zeitabschnitt in der Vergangenheit betrachten. Diese Inflexibilität ist scheinbar auch den Entwicklern hinter Java aufgefallen und wurde mit "JEP 349: JFR Event Streaming" angegangen. Wie der Name schon vermuten lässt, ist der Gedanke dahinter, Events on-the-fly und kontinuierlich weiterzuverarbeiten. Damit wird JFR zum Beispiel auch für Anforderungen gerechnet, die Events für eine Monitoring Lösung einzusetzen. JFR Event Streaming ist ab Java 14 verfügbar und lässt sich über eine einfache API verwenden.

  • Als Erstes erstellt man über new eine Instanz von RecordingStream.
  • Dann aktiviert man die Events über enable(...), an denen man ein Interesse hat. Hier hat man über eine Fluent-Api weitere Möglichkeiten, z.B. einen Threshold oder eine Periode einzustellen, um die Anzahl der Events zu reduzieren.
  • Im nächsten Schritt definiert man über onEvent(...) einen Callback, der die eingehenden Events verarbeitet. Der Callback erhält die Events in der Form von jdk.jfr.consumer.RecordedEvent, was eine generische Sicht auf ein Event liefert. Möchte man auf die nicht Standard-Eigenschaften des Events zugreifen, kann man je nach Datentyp die getter-Methoden wie getString(...), getInt(...) usw. verwenden.
  • Zuletzt muss man den Stream starten. Mit start() startet man blockierend im aktuellen Thread. Alternativ kann man mit startAsync() die Events auch in einem separaten Thread konsumieren.
Fazit
Der Java Flight Recorder bietet eine interessante und frische Möglichkeit, das Verhalten einer Java Anwendung im Auge zu behalten. Die Schnittstellen sind sehr effektiv gehalten und fühlen sich stabil an. Das Java Mission Control ist ein mächtiges Werkzeug, in dem man sicher immer mal wieder neue und interessante Funktionen und Einblicke entdecken kann. JFR verbindet Logging und Metriken zu einem spannenden Werkzeug in der Java Welt.

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*Pflichtfelder

*

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.