- Une régression de performance inattendue s'est produite lors de la migration de la base de code de Scala 2.13 vers Scala 3
- Dans les environnements de test et de déploiement initiaux, toutes les métriques étaient normales, mais quelques heures plus tard le lag Kafka a augmenté
- Les tests de charge ont confirmé une forte baisse de throughput lors du traitement de messages décomposés
- L'analyse avec async-profiler a révélé qu'un bug d'évaluation inefficace de chaînes dans la bibliothèque Quicklens était la cause
- Après la mise à jour de la bibliothèque, les performances ont été rétablies, en soulignant la nécessité de faire attention aux différences de comportement des bibliothèques entre versions de Scala
Processus de migration du service
- Le service existant a été migré de Scala 2.13 vers Scala 3.7.3
- Il s'agissait d'un service orienté collecte de données sans macros, avec des performances critiques
- Après avoir appliqué les dépendances, les options du compilateur, et les changements de types et de syntaxe, la compilation a réussi
- En environnement de test et lors du déploiement progressif, les logs et métriques sont tous normaux
- Les indicateurs aux niveaux infrastructure, JVM et application étaient également en bonne santé
Dégradation de performance d'origine inconnue
- Environ 5 à 6 heures après le déploiement, une hausse du lag Kafka est apparue
- Une baisse du throughput par instance s'est produite même sans pic de données
- Après rollback, le throughput s'est rétabli immédiatement, confirmant que le changement de code en était la cause
Analyse des performances et recherche de la cause
- En test de charge, la régression de performance n'a pas été reproduite au départ
- Une chute du throughput s'est produite uniquement lorsque les messages étaient décomposés et avec des payloads hétérogènes
- Les dépendances de bibliothèque (sérialisation, SDK DB, image Docker, bibliothèque de configuration, etc.) ont été testées en les rétablissant une par une, sans aucun changement
- Après exécution du profiling CPU avec async-profiler :
- En Scala 3, la part CPU du compilateur JIT et de l'étape de décodage a fortement augmenté
- Sur le flamegraph, les appels Quicklens représentaient près de la moitié du temps CPU total
- En Scala 2.13, le même appel ne représentait que 0,5 %
Cause racine
- Un bug d'évaluation inefficace de chaînes de la bibliothèque Quicklens se produisait sous Scala 3
- La correction associée est intégrée dans GitHub PR #115
- Après la mise à jour de la bibliothèque, la différence de performance entre Scala 3 et 2.13 a été résolue
Leçons et recommandations
- Une dépendance à la métaprogrammation des bibliothèques peut provoquer des écarts de performance entre versions de Scala
- Même quand une migration se termine correctement, il faut benchmarker les hotspots et les goulots d'étranglement
- Pour les services où la performance est critique, une validation basée sur des mesures réelles est indispensable au lieu de supposer que ça fonctionne
- Des vérifications préventives sont nécessaires pour éviter une situation où ce sont les benchmarks qui révèlent les goulots d'étranglement que le code ne montre pas
Aucun commentaire pour le moment.