4 Punkte von GN⁺ 2025-12-09 | 1 Kommentare | Auf WhatsApp teilen
  • 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

1 Kommentare

 
GN⁺ 2025-12-09
Hacker-News-Kommentare
  • Ich bin kein Scala-Fan, aber der gründlich analysierte und debugte Prozess war beeindruckend.
    So sollten technische Blogposts geschrieben sein. Es ist schwer vorstellbar, dass AI solche Denkprozesse auf diesem Niveau ersetzt.
    • Beim Refresh eines unserer Services sind wir von Scala 2.13 auf Scala 3 migriert.
      Die erste Frage war einfach: „Warum sollten wir überhaupt upgraden?“
  • In Scala 3 ist das Schlüsselwort inline Teil des Makro-Systems.
    Wenn man inline bei Parametern verwendet, weist man den Compiler an, den Ausdruck am Aufrufort zu inlinen.
    Wenn das groß wird, belastet das den JIT-Compiler erheblich.
    In Scala 2 war @inline nur ein Hinweis, aber in 3 wird es zwingend angewendet.
    Daher ist es ein großer Fehler, einfach @inline durch inline zu ersetzen.
    • Dieser Unterschied ähnelt dem, was früher mit dem register-Schlüsselwort in C/C++ passiert ist.
      Anfangs war es zwingend, aber mit besseren Optimierungen wurde es nur noch eine Empfehlung und schließlich ignoriert.
      inline in C++ hat einen ähnlichen Weg genommen.
    • Kotlin verwendet inline fast überall aktiv.
      Bei Funktionen wie map, um den Lambda-Overhead zu vermeiden.
      Leistungsprobleme gab es kaum, aber in Kombination mit Scalas Makro-System könnten komplexe Ausdrücke Probleme verursachen.
  • Nach dem Upgrade der Bibliotheken war die Performance von Scala 3 fast identisch mit Scala 2.13.
    Ich hatte eine ähnliche Erfahrung beim Upgrade von Ruby 2 auf 3.
    Man sollte nicht nur die Sprache selbst anheben, sondern den gesamten Dependency-Stand aktualisieren, damit das System stabil bleibt.
  • Das Problem mit Scala 3 ist, dass es niemand wollte.
    Die Probleme der Typinferenz aus Scala 2 sind noch immer nicht gelöst, stattdessen wurde nur die Sprache verändert.
    Es ist, als hätte man die Marktanforderungen ignoriert und ein Produkt gebaut, das niemand wollte.
    PS: Man sollte wirklich eine echte Unit-Test-Suite für den Compiler bauen.
    • Traurig, aber ich stimme zu. Scala wirkte etwa 2010–15 vielversprechend.
      Aber der Scala-3-Rewrite hat die Kompiliergeschwindigkeit und Tooling-Probleme nicht gelöst und dem Projekt seinen Schwung komplett genommen.
      Ich frage mich, ob 2025 noch jemand ein neues Projekt mit Scala anfangen würde.
    • Ich habe mehrmals versucht, Scala zu lernen, bin aber am Ende immer wieder zu Clojure zurückgekehrt.
      Scala wirkt wie eine von Akademikern gebaute Sprache, und dass sie in der Industrie zeitweise populär war, erscheint eher ungewöhnlich.
    • Das trifft den Kern gut.
      Jetzt müssen alle Tools auf Scala 3 angepasst werden, und selbst IntelliJ unterstützt es noch nicht vollständig.
      Es wäre besser gewesen, Scala 2 schrittweise zu verbessern; stattdessen scheint man sich nur auf den akademischen Erfolg konzentriert zu haben.
      Zum Beispiel gibt es selbst über early return viel Streit, wie in tpolecats Artikel, während Kotlin das problemlos unterstützt.
    • Die Aussage „Es gibt keine Tests“ ist Falschinformation.
      Der Scala-Compiler hat Tausende, Zehntausende Tests, und
      das offizielle Testverzeichnis sowie das
      Community-Build-System prüfen Millionen LOC.
    • Anscheinend wurde der Artikel nicht richtig gelesen. Der Punkt geht völlig vorbei.
  • Am interessantesten an diesem Artikel fand ich, dass man automatisierte Performance-Tests und Flamegraph-Analysen standardmäßig haben sollte.
    Gerade bei großen Änderungen wie einem Sprachversions-Upgrade ist das unverzichtbar.
    • Benchmark-Tests brauchen im Unterschied zu normalen Tests eine feinere Abstimmung.
      Wir benchmarken kontinuierlich ein in C++ geschriebenes Tool, aber wegen Umgebungsrauschen ist es schwer, konsistente Ergebnisse zu bekommen.
      Wir überlegen, es mehrfach auf derselben Maschine auszuführen und dann zu vergleichen.
    • Ich frage mich, welche Performance-Test-Tools man heute auf der JVM verwendet.
  • Das einzige Problem von Scala 3 ist Python-Neid.
    Das Problem war, eine zweite Syntax zu schaffen und sie als Zukunft zu verkaufen.
    Dadurch wurde auch das Tooling-Ökosystem langsamer.
    • Inzwischen unterstützen die meisten Tools die neue Syntax.
      Mit dem Compiler oder scalafmt kann man den Stil auch automatisch umwandeln.
    • Ganz im Scala-Stil kann man dieselbe Sache nun auf mehrere Arten tun.
      Jetzt gibt es doppelt so viele Varianten: Klammer-Syntax und Einrückungs-Syntax.
    • Ein Vergleich mit Haskell wäre vielleicht reizvoller gewesen.
    • Als früherer Scala-Fan war ich von den Beispielen der neuen Syntax irritiert.
      Die match-Syntax wirkt zu weitschweifig und wie eine Python-Kopie.
  • Ich habe früher schon eine Scala-2.x-Migration gemacht, und das Schwierigste war das Warten auf Dependencies.
    Damals bekam Scala dank Spark viel Aufmerksamkeit, verpasste aber die Chance, sich als kommerzielle Sprache zu etablieren.
    Heute ist Spark bei Python gelandet, und den Platz der modernen JVM-Sprache hat Kotlin eingenommen.
    Am Ende wirkt es, als sei Scala wieder zu einer akademischen Sprache geworden.
    • Aber Scala wird in großen Unternehmen weiterhin breit eingesetzt.
      Das zeigt auch der Scala Adoption Tracker.
      Die neuen Funktionen von Scala 3 haben das Potenzial, das Sprachökosystem erneut zu innovieren.
      Zum Beispiel: Erklärung zu Capture Checking
    • Ob Kotlin die JVM wirklich beherrscht, ist fraglich.
      Java hat durch funktionale Features einen Teil von Scalas Attraktivität absorbiert.
    • Auf serverseitiger JVM ist Kotlin kaum präsent.
      Meiner Erfahrung nach ist auch die Marktnachfrage minimal.
    • Kotlin ist faktisch eine nur für Android gedachte Sprache.
      Das liegt nur daran, dass Google die Java-Unterstützung eingeschränkt hat.
      Im gesamten JVM-Markt kommt Kotlin nur auf etwa 10 % Anteil.
  • Ich fand es merkwürdig, auf Scala 3 zu wechseln, ohne die Bibliotheksversionen zu aktualisieren.
    Wenn man Security-Audits (PIC-DSS usw.) durchläuft, ist das Aktuellhalten von Bibliotheken zwingend.
    • Die Aussage „aktuell bleiben ist eine gute Gewohnheit“ ist eine Formulierung, die Diskussionen abwürgt.
      Ich neige eher dazu, Dependencies lange in älteren Ständen zu halten.
      Neue Versionen bringen neue Bugs mit, dazu Wechsel bei Maintainers oder Sicherheitsrisiken.
    • Ich war auch verwirrt. Im Artikel hieß es, man habe „Dependencies aktualisiert“, später aber, dass „nach dem Update die Performance gleich geworden sei“.
      Anfangs wurde wohl nur ein Teil aktualisiert. In kleine Schritte zu zerlegen ist üblich, aber hier hatten sie wohl Pech.
    • Als die Ursache des Bugs klar war, war es weniger beeindruckend.
      Das Problem war nicht Scala 3 selbst, sondern das Zusammenspiel mehrerer Faktoren.
    • Je größer eine Änderung ist, etwa ein Sprachversions-Upgrade, desto mehr sollte man immer nur eine Sache auf einmal ändern.
    • Mit Versionsbeschränkungen in Maven/Gradle/SBT bleibt das unabhängig von der Sprachversion beherrschbar.
      Man muss nur aufpassen, weil Scala-spezifische Bibliotheken die Scala-Version oft im Versionsschema enthalten.
  • Der Bugreport von SoftwareMill und Scala GitHub war eine kleine, aber präzise Korrektur.
    Scalas Ausdruckskraft und Typsicherheit kamen gut zur Geltung.
    Wie in Li Haoyis Artikel gezeigt, ist Scala auch als Python-Alternative attraktiv genug.
  • Die wichtigste Lehre ist, dass man bei Major-Upgrades von Sprachen oder Frameworks auch die Bibliotheken gemeinsam aktualisieren sollte.
    Das ist besonders wichtig, je mehr Bibliotheken mit magischen Features überladen sind.