- Während der Migration der Codebasis von Scala 2.13 auf Scala 3 kam es zu unerwartetem Performance-Verlust
- In Test- und Deployment-Umgebungen waren anfangs alle Metriken normal, aber nach einigen Stunden stieg der Kafka-Lag
- Bei den Load Tests wurde ein Durchsatzabfall bei fein granularer Nachrichtenverarbeitung festgestellt
- Durch die async-profiler-Analyse zeigte sich, dass ein Bug in der Kettenauswertung der Quicklens-Bibliothek die Ursache war
- Nach dem Update der Bibliothek erholte sich die Leistung, was die Notwendigkeit unterstreicht, Leistungsunterschiede zwischen Scala-Versionen in Bibliotheken zu beachten
Migrationsprozess des Services
- Der bestehende Service wurde von Scala 2.13 auf Scala 3.7.3 migriert
- Es handelte sich um einen datensammelnden Service ohne Einsatz von Makros, bei dem Leistung eine kritische Komponente ist
- Nach dem Anwenden von Abhängigkeits-, Compiler-Optionen sowie Typ- und Syntaxänderungen war der Compile erfolgreich
- In Testumgebung und gestuftem Deployment wurden Logs und Metriken ebenfalls als normal gemeldet
- Infrastruktur-, JVM- und Anwendungsebenen-Metriken wurden durchgehend als gesund eingestuft
Unklare Ursache der Leistungsabnahme
- Etwa 5 bis 6 Stunden nach dem Rollout trat ein Anstieg des Kafka-Lags auf
- Auch ohne Daten-Spikes sank die Verarbeitungsrate pro Instanz
- Nach einem Rollback stieg die Durchsatzrate sofort wieder an, wodurch bestätigt wurde, dass die Codeänderung die Ursache war
Leistungsanalyse und Ursachenforschung
- In den Lasttests ließ sich die Performance-Regressions initial nicht reproduzieren
- Der Durchsatzabfall trat nur bei feingranularer Verarbeitung und heterogenen Payloads auf
- Durch sequentielles Zurücksetzen abhängiger Bibliotheken (Serialization, DB SDK, Docker-Image, Konfigurationsbibliotheken usw.) ergaben sich keine Änderungen
- Die CPU-Profilsanalyse mit async-profiler ergab, dass
- in Scala 3 die CPU-Auslastung von JIT-Compiler und Decoding-Phase stark anstieg
- im Flamegraph belegt ein Quicklens-Aufruf die Hälfte der gesamten CPU-Zeit
- in Scala 2.13 machte derselbe Aufruf nur rund 0,5 % aus
Grundursache
- In der Quicklens-Bibliothek trat in Scala 3 ein Bug mit ineffizienter Kettenauswertung auf
- Die zugehörige Korrektur ist in GitHub PR #115 enthalten
- Nach dem Update der Bibliothek wurde der Performance-Unterschied zwischen Scala 3 und 2.13 behoben
Lektionen und Empfehlungen
- Eine metaprogrammierende Abhängigkeit von Bibliotheken kann zu Performance-Unterschieden zwischen Scala-Versionen führen
- Auch wenn eine Migration erfolgreich abgeschlossen ist, sollten Hotspots und Engpässe benchmarked werden
- In Leistungs-kritischen Services ist eine Validierung auf Basis realer Messdaten zwingend erforderlich, statt nur zu unterstellen, dass „es funktioniert“
- Vorbeugende Checks sind erforderlich, um Situationen zu vermeiden, in denen der Benchmark statt des Codes den Engpass offenlegt
Noch keine Kommentare.