2024-01-18 12:20:00
Dans les articles précédents sur le thème de la journalisation Java (Bonnes pratiques, façades de journalisation), j’ai déjà mentionné qu’il existe une multitude de bibliothèques Java sur le thème de la journalisation. Après avoir clarifié dans le dernier article comment combiner différents enregistreurs avec une façade, nous souhaitons maintenant examiner les performances des bibliothèques de journalisation.
Publicité
Hendrik Ebbers (@hendrikEbbers) est champion Java, membre du groupe d’experts JCP et a été reconnu à plusieurs reprises comme conférencier JavaOne Rockstar. Avec sa propre société Open Elements, Hendrik participe actuellement à la conception du Hedera Hashgraph et à la mise à disposition de ses services au public. Hendrik est co-fondateur de JUG Dortmund et de Cyberland et donne des conférences et des ateliers sur Java dans le monde entier. Son livre « Mastering JavaFX 8 Controls » a été publié par Oracle Press en 2014. Hendrik travaille activement sur des projets open source tels que JakartaEE ou Eclipse Adoptium. Hendrik est membre du TSC AdoptOpenJDK et de l’Eclipse Adoptium WG.
Mesure des performances en Java
Java dispose d’un outil pour vérifier de petites parties d’une application ou d’une bibliothèque Java à l’aide d’un benchmark Harnais de microbenchmark Java (JMH), qui est fourni par OpenJDK pour effectuer des tests de performances. Semblable aux tests unitaires, il exécute et analyse de petites parties de l’application (micro-benchmarks). Entre autres choses, vous pouvez définir si le code doit s’exécuter plusieurs fois pendant quelques secondes sans mesurer afin de « réchauffer » la JVM et le JIT.
Dans JMH, ces paramètres et d’autres peuvent être facilement définis à l’aide d’annotations, similaires à JUnit. Un exemple simple de benchmark ressemble à ceci :
@Benchmark
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 4, time = 4)
@Measurement(iterations = 4, time = 4)
public void runSingleSimpleLog() {
logger.log("Hello World");
}
L’exemple effectue quatre cycles de préchauffage, suivis de quatre cycles de mesure. Chaque exécution dure quatre secondes et le résultat de la mesure indique le nombre d’opérations effectuées par seconde. Plus précisément, cela signifie à quelle fréquence « Hello World » peut être enregistré. Après l’exécution, le tout est affiché dans un tableau dans la ligne de commande, mais vous pouvez également l’enregistrer sous forme de fichier JSON ou CSV, par exemple.
Mesure des performances des enregistreurs Java
À l’aide de JMH, j’ai créé un benchmark open source pour les frameworks de journalisation qui peut être consulté sur GitHub. Il vérifie actuellement les performances des bibliothèques et configurations de journalisation suivantes :
- JuL (java.util.logging) avec connexion à la console
- JuL (java.util.logging) avec journalisation dans un fichier
- JuL (java.util.logging) avec journalisation sur la console et sur un fichier
- SLF4J Simple avec connexion dans un fichier
- Log4J2 avec connexion à la console
- Log4J2 avec journalisation dans un fichier
- Log4J2 avec journalisation sur la console et sur un fichier
- Log4J2 avec journalisation asynchrone dans un fichier
- Chronicle Logger avec journalisation asynchrone dans un fichier
Pour chacune de ces constellations, il existe différents benchmarks qui mesurent les performances depuis la création de l’enregistreur jusqu’à la journalisation d’un simple message “Hello World” jusqu’aux appels de journalisation complexes (espace réservé dans le message, marqueur, utilisation du MDC, etc.).
Les mesures montrent que les frameworks de journalisation sont généralement très performants. D’un autre côté, ils ont également révélé quelques résultats qui ne sont certainement pas immédiatement clairs pour tout le monde.
Vous trouverez ci-dessous un aperçu des résultats de mesure obtenus lors de l’enregistrement simple d’un message « Hello World » :
Le problème avec la console
Un premier résultat des mesures est que la journalisation sur la console est toujours nettement plus lente que la journalisation sur le système de fichiers. Bien que vous puissiez atteindre 200 000 à 300 000 appels d’enregistreur par seconde lors de la connexion à un fichier, le nombre d’opérations par seconde lors de la sortie vers les consoles a toujours été bien inférieur à 100 000. Puisque toutes les bibliothèques de journalisation sont incluses ici System.out
ou. System.err
fonctionne, la bibliothèque que vous utilisez ne fait pratiquement aucune différence en termes de performances. À l’avenir, il sera passionnant de voir si nous pouvons obtenir de meilleures performances grâce à des astuces ou à des modifications.
Journalisation des fichiers synchronisés et asynchrones
Vous pouvez constater une autre grande différence lorsque vous examinez les valeurs mesurées à partir de l’enregistrement synchrone ou asynchrone dans un fichier. Il devient immédiatement évident que la journalisation asynchrone est nettement plus rapide. Les tableaux suivants présentent les métriques de la journalisation asynchrone par rapport à la journalisation synchrone :
Les performances nettement supérieures sont dues au fait que l’écriture des enregistreurs asynchrones n’est pas bloquée. Les enregistreurs Log4J2 et Chronicle Logger utilisent des bibliothèques différentes en interne, mais sont tous deux basés sur une « bibliothèque de communication inter-thread sans verrouillage ». Chez Log4J ici Perturbateur LMAX doit être ajouté en tant que bibliothèque qui permet la journalisation asynchrone en interne via un tampon en anneau, le Chronicle Logger est basé directement sur cela Bibliothèque de files d’attente de chroniques.
Une description spécifique des bibliothèques utilisées en interne et de la manière dont elles permettent une communication asynchrone ou une écriture sur le système de fichiers peut être trouvée dans la documentation.
Si vous comparez les performances de Log4J2 et de Chronicle Logger, vous pouvez voir que Chronicle Logger est nettement plus rapide. Cependant, cet avantage en termes de performances s’accompagne également d’un inconvénient dont vous devez être conscient : alors que Log4J2 continue de générer une journalisation ligne par ligne dans le système de fichiers qui est facile à lire pour les humains, même en mode asynchrone, le Chronicle Logger écrit tous les messages au format binaire. Des outils sont nécessaires pour la lecture ou l’analyse, fournis par l’enregistreur. De plus, la variance des résultats du test Chronicle Logger est nettement plus élevée. Je soupçonne que la raison est que la file d’attente de chronique utilisée en interne gère les données binaires pour l’écriture de la journalisation et ajuste toujours dynamiquement ses tailles. Cependant, cela doit encore être approfondi. Le tableau suivant donne un aperçu de l’écart :
Conclusion
Comme vous pouvez le constater, non seulement le choix d’une bibliothèque de journalisation, mais également sa configuration sont extrêmement importants pour les performances. Bien que la connexion à la console pendant le développement soit certainement très pratique, vous pouvez, par exemple, vous demander si l’utilisation de la connexion à la console en fonctionnement réel est vraiment toujours nécessaire. Cela montre également que l’utilisation d’enregistreurs asynchrones peut avoir du sens si les performances du système sont vraiment critiques. Bien entendu, cela s’accompagne d’une plus grande complexité et de dépendances transitives supplémentaires. En fin de compte, chaque projet doit décider lui-même quel enregistreur est le plus judicieux. Les chiffres mentionnés ici fournissent désormais une base supplémentaire pour le déterminer.
(moi)
#Développement #logicielles #performances #journalisation #Java
1705586295