Java Flight Recorder (JFR) est une fonctionnalité de la JVM qui après activation enregistre des événements émis par son activité mais aussi celle de l’application et même du système d’exploitation avec un très faible overhead. Il est possible d’émettre ses propres événements et même de consommer des événements grâce à une API de Java 14. Depuis Java 11, JFR est open source et il est donc utilisable maintenant en production sans licence commerciale. L’exploitation de ces événements avec l’outil JMC peut être particulièrement appréciable lors d’activité de profiling et de monitoring. Cette session sera l’occasion de faire un tour d’horizon de ces fonctionnalités qui peuvent s’avérer utiles pour certaines problématiques.
2. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 2
La JVM
• Sûrement l’élément le plus important de la plate-forme Java
• Mais c’est une boîte noire
• Besoin d’outillage pour obtenir des informations
Si l’exécution ne se passe pas comme prévue
Exécute du byte-code ou du code natif
Gère les interactions avec le système hôte (threads, I/O, off heap, …)
Optimise les performances (JIT de niveau 1 et 2)
Assure la gestion de la mémoire (Ramasse-miettes)
3. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 3
Profiling et monitoring
Des difficultés surviennent, notamment en production
Difficile de reproduire un cas dans un autre environnement
Scénarios
Volume de données
Timing
Un besoin croissant de monitoring
Notamment avec les architectures distribuées
4. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 4
Les outils historiques
• Outils commerciaux
• Outils du JDK
JConsole
JVisualVM
Plus fourni depuis le JDK 9,
Mis en open source, téléchargeable sur GitHub
• Outils open source
Arthas
5. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 5
JFR et JMC
• Depuis Java 7u40 dans le JDK d’Oracle
• Mis en open source dans Java 11
• D’où le changement de noms :
• JavaDK Flight Recorder (JFR)
• JavaDK Mission Control (JMC)
6. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 6
Jean-Michel Doudoux
http://www.jmdoudoux.fr
@jmdoudoux
Co-fondateur du , membre du
Auteur de 2 didacticiels
Diffusés sous licence GNU FDL
• Développons en Java (4001 pages)
• Développons en Java avec Eclipse
CTO et
8. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 8
Roadmap
• Les API pour JFR
• Les événements personnalisés
• Créer et parser un fichier JFR par API
• L'API Event Streaming
• L’écosystème autour de JFR
• Présentation de
• JavaDK Flight Recorder (JFR)
• JavaDK Mission Control (JMC)
• L’outil jfr du JDK
10. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 10
Analogie avec l’aéronautique
• Enregistre des informations durant le vol
• Exploitables à postériori
• Pour trouver les causes d’un incident ou d’un accident
Souvent en cas de crash
Pour améliorer la fiabilité
Pour résoudre des problèmes (cf Boeing 737 Max récemment)
• Une des boîtes noires (Flight Data Recorder)
• Dans l’automobile européenne
Depuis mai 2022 pour les véhicules neufs
11. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 11
JavaDK Flight Recorder
• Inclus dans la JVM HotSpot
• Collecte des événements
Configurable
De différents artéfacts (JVM, système, application)
• Faible overhead
Car inclus au cœur de la JVM Hotspot
• Permettant une utilisation en production
12. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 12
Conditions d’utilisation
• Fourni dans la distribution Oracle avant Java 11
• Utilisable gratuitement en dev
• Requiert une licence en production
Une des raisons de l’acceptation d’une licence lors du téléchargement
• Open source dans OpenJDK depuis Java 11 (JEP 328)
Activé par défaut
• Backport dans OpenJDK 8u272
• Et l’utilisation de 2 options de la JVM pour l’activation
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder
13. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 13
Les éléments de JFR
• Les enregistrements (recordings)
sont gérés (start, stop, dump sur disque, …)
chacun possède sa propre configuration
• Les événements (events)
contiennent les données et méta-données
relatifs à un état ou une activité
de la JVM, de l’application ou du système
fournis en standard ou créés via une API
• Les configurations (settings)
activation et configuration de chaque événement
14. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 14
Les événements
• Les informations collectées sont des events, de 4 types :
• Instant event :
Événement émis une fois
Les données sont associées au moment de la capture
Exemple : démarrage d’un thread
• Timed events :
Événements de type Duration avec un seuil défini
• Duration event :
Événement qui possède une heure de début et de fin
Exemple : exécution du ramasse-miettes
• Requestable event :
Événement émis selon une certaine période
Exemple : utilisation de la CPU toutes les secondes
15. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 15
La collecte en interne
• JFR collecte des événements en mémoire dans des buffers
• Afin de réduire l’overhead de JFR
• Pour être éventuellement écrits dans un fichier binaire
17. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 17
Gestion des enregistrements
avec les options de la JVM
• Gestion statique, au lancement de la JVM
• Pratique pour des tests par exemple
• Utilisation de l’option -XX:StartFlightRecording
Qui proposent plusieurs paramètres
$ java -XX:StartFlightRecording=duration=1h,filename=monapp.jfr com.oxiane.MonApp
$ java -XX:StartFlightRecording=delay=20s,duration=60s,dumponexit=true,filename=monapp.jfr
com.oxiane.MonApp,settings=profile
18. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 18
Gestion des enregistrements
avec jcmd
• Gestion dynamique, sur une JVM en cours d’exécution
Utilisable même en production
• Invocation de commandes JFR.xxx sur le pid de la JVM
Qui proposent des paramètres
$ jcmd <pid> JFR.start name=monrecording maxage=4h maxsize=400MB
• jcmd <pid> JFR.start <options>
$ jcmd <PID> JFR.dump name=monrecording filename=monrecording.jfr
• jcmd <pid> JFR.dump <options>
• jcmd <pid> JFR.check
• jcmd <pid> JFR.configure <options>
• jcmd <pid> JFR.stop
20. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 20
Les configurations standards
• OpenJDK en propose 2 standard :
Dans le sous-répertoire lib/jfr du JDK
• Default
Configuration à très faible overhead (généralement < 1%)
Pour monitoring en continu en prod
• Profile
Configuration à faible overhead (généralement < 3%)
Pour profiling
• Possibilité de créer ses propres configurations
Edition du fichier XML
ou utilisation de JMC
ou de l’outil jfr du JDK (depuis Java 17)
21. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 21
Les événements standards
• Le nombre d’événements fournis en standard varie :
OpenJDK 11 : 136 OpenJDK 15 : 157
OpenJDK 12 : 136 OpenJDK 16 : 159
OpenJDK 13 : 143 OpenJDK 17 : 167
OpenJDK 14 : 145 OpenJDK 18 : 165
• Attention en Java 16 : nouvel event jdk.ObjectAllocationSample
Remplace les events jdk.ObjectAllocationInNewTLAB et jdk.ObjectAllocationOutsideTLAB
Activé par défaut dans les 2 configurations standard
Si la vue « TLAB Allocations » de JMC est vide
Utiliser la dernière version de JMC ou modifier les configurations
• Nouveau en Java 17, pour obtenir la liste :
C:>jfr metadata
24. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 24
Java Mission Control
• Historiquement fourni avec JRockit
• Intégré dans le JDK Oracle depuis Java 7u40
• Retiré du JDK et mis en open source en Java 11
• Dans un sous-projet d’OpenJDK
• Renommé JDK Mission Control
25. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 25
Les différentes versions
• 5.5 (mars 2015)
• 6.0 : support de Java 9
• 7.0 : première version open source (décembre 2019)
• 8.0 (janvier 2021)
• 8.1 (août 2021) : requiert Java 11
• 8.2 (mars 2022)
• Attention à la compatibilité
Avec la version de la JVM utilisée pour créer les fichiers .jfr
26. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 26
Fournisseurs de binaires
• N’étant plus fournis avec le JDK 11, il faut le télécharger
• Plusieurs fournisseurs proposent des binaires de JMC :
• AdoptOpenJDK
https://adoptopenjdk.net/jmc.html
• Azul (Azul Mission Control)
https://www.azul.com/products/components/zulu-mission-control/
• Oracle
https://jdk.java.net/jmc/
• Possibilité de télécharger les sources et construire le binaire
• Adoptium (Eclipse Mission control)
https://adoptium.net/jmc
27. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 27
Les fonctionnalités proposées
• Développées sur une base Eclipse RCP
Donc extensible par plugins
• 3 plugins fournis par défaut
• JVM Browser
• Une console JMX
• Java Flight Recorder
30. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 30
Lancer un enregistrement JFR
• Trois étapes via un assistant :
• Informations générales
• Configuration des événements
• Détails des informations des événements
• Gestion des templates (modèles de configurations)
32. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 32
Java Flight Recorder plugin
• Pour exploiter et analyser les fichiers JFR
Grâce à diverses vues et graphiques qui affichent les événements
• L’ouverture d’un fichier se fait dans un onglet
Avec l’affichage d’un résumé de son analyse
37. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 37
Java Flight Recorder plugin
• La vue « Event Browser » pour visualiser tous les events
avec filtrage sur le nom
• Exemple avec l’event jdk.FinalizerStatistics ajouté en Java 18
39. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 39
L’outil jfr du JDK
• OpenJDK 11 propose l’outil en ligne de commande jfr
Pour manipuler des fichiers .jfr
• Afficher les événements
$ jfr print [--xml|--json] [--categories <filter>] [--events <filter>]
[--stack-depth <depth>] <fichier>
• Afficher des infos générales sur l’enregistrement
$ jfr summary <fichier>
• Regrouper des chunks dans un fichier
$ jfr assemble <repertoire> <fichier>
• Découper un fichier en plusieurs
$ jfr disassemble [--output <repertoire>] [--max-chunks <chunks>] [--max-size
<taille>] <fichier>
40. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 40
L’outil jfr du JDK
• En Java 17, facilite la création d’une configuration
• De manière interactive en mode CLI grâce à 12 questions
$ jfr configure --interactive
============== .jfc Configuration Wizard ============
This wizard will generate a JFR configuration file by
asking 12 questions. Press ENTER to use the default
value, or type Q to abort the wizard.
Garbage Collector: Normal (default)
1. Off
2. Normal
3. Detailed
4. High, incl. TLABs/PLABs (may cause many events)
5. All, incl. Heap Statistics (may cause long GCs)
• Ou la modification d’une configuration existante
$ jfr configure +jdk.Deserialization#enabled=true+jdk.Deserialization#stackTrac
e=true --input custom.jfc --output custom.jfc
42. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 42
Création d’un événement
• Définition simple : une classe qui hérite jdk.jfr.Event
• Des annotations
Pour les méta-données
De configuration
import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Enabled;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.StackTrace;
@Name("com.oxiane.MonEvent")
@Label("MonEvent")
@Description("Mon evenement")
@Category("Metrique")
@Enabled(true)
@StackTrace(true)
public class MonEvent extends Event {
@Label("Message")
@Description("Description du message")
public String message;
}
45. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 45
Créer un fichier JFR
• Utiliser la classe jdk.jfr.Recording
• Démarrer et arrêter l’enregistrement
Path path = Paths.get("mon_event_recording.jfr");
try (Recording recording = new Recording()) {
recording.setName("Mon event recording");
recording.enable(MonEvent.class);
recording.start();
// ...
recording.stop();
recording.dump(path);
}
• Faire un dump des événements dans un fichier
46. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 46
Parser un fichier JFR
• Utiliser les classes
jdk.jfr.consumer.RecordingFile et jdk.jfr.consumer.RecordedEvent
try (RecordingFile recordingFile = new RecordingFile(Paths.get("recording.jfr"))) {
while (recordingFile.hasMoreEvents()) {
RecordedEvent event = recordingFile.readEvent();
if (event.getEventType().getName().equals("com.oxiane.jfr.event.MonEvent")) {
System.out.println(event);
}
}
}
48. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 48
JFR Event Streaming
• JEP 349 : un nouveau mode d’utilisation de JFR
Pour la consommation des événements
• Propose une API pour le support du streaming d’événements
Exploitable en temps réel, des événements auxquels on est abonnés
Sans avoir à passer par un fichier
• Exploitation des événements en deux étapes :
S’abonner aux types particuliers d’événements
Enregistrer un handler invoqué lorsqu’un événement est émis
• Facilite le développement de fonctionnalités de monitoring
49. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 49
JFR Event Streaming
• En utilisant une des configurations existantes
• Ou en définissant sa propre configuration
try (var rs = new RecordingStream()) {
rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
rs.enable("jdk.JavaMonitorEnter").withThreshold(Duration.ofMillis(10));
rs.enable("com.oxiane.MonEvent");
rs.onEvent("com.oxiane.MonEvent", System.out::println);
rs.onEvent("jdk.GarbageCollection", System.out::println);
rs.onEvent("jdk.CPULoad", System.out::println);
rs.start();
}
Configuration config = Configuration.getConfiguration("default");
try (var rs = new RecordingStream(config)) {
rs.onEvent("jdk.GarbageCollection", System.out::println);
rs.onEvent("jdk.CPULoad", System.out::println);
rs.start();
}
52. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 52
JUnit 5
• Depuis la version 5.7, peut lever des events JFR
• Fonctionnalité expérimentale
• Ajout d’une dépendance
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-jfr</artifactId>
<version>1.8.1</version>
<scope>test</scope>
</dependency>
53. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 53
JfrUnit
• Pour des tests avec vérifications sur des events JFR
• Ecrit par Gunnar Morling
https://github.com/moditect/jfrunit
<dependency>
<groupId>org.moditect.jfrunit</groupId>
<artifactId>jfrunit</artifactId>
<version>1.0.0.Alpha1</version>
<scope>test</scope>
</dependency>
• Requiert Java 16 minimum
• Mise en œuvre :
La classe de test doit être annotée avec @JfrEventTest
L'annotation @EnableEvent pour s'abonner à un event
La méthode JfrEvents::awaitEvents() permet d'attendre les évents émis
54. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 54
JfrUnit
• Exemple
import static org.moditect.jfrunit.JfrEventsAssert.*;
import static org.moditect.jfrunit.ExpectedEvent.*;
import org.junit.jupiter.api.Test;
import org.moditect.jfrunit.EnableEvent;
import org.moditect.jfrunit.JfrEventTest;
import org.moditect.jfrunit.JfrEvents;
@JfrEventTest
public class MonServiceTest {
public JfrEvents jfrEvents = new JfrEvents();
@Test
@EnableEvent("com.oxiane.MonEvent")
void taiterTest() {
MonService.traiter();
jfrEvents.awaitEvents();
assertThat(jfrEvents).contains(event("com.oxiane.MonEvent"));
}
}
56. #ApresJava9 #voxxeddaysLU
#ProfilingMonitoringJDK 56
Utilisez JFR et JMC
• Le but était de présenter rapidement JFR et JMC
• Faible overhead
-> Utilisable en production
gratuitement depuis Java 11 et 8u272
• Les API utilisables
Notamment pour émettre ses propres événements
Ou pour streamer des événements depuis Java 14
• Outils puissants pour le profiling et le monitoring
• L’écosystème qui se développe autour de JFR
• Si ce n’est pas encore fait, ajoutez les à votre boîte à outils