Für ein internes Werkzeug mit REST-API sollte die Auslieferung als kleines, schnell startendes natives Binary erfolgen.
Als Framework standen Spring Boot und Micronaut zur Auswahl, im Team gab es vor allem Spring-Erfahrung.
Statt nach Bauchgefühl zu entscheiden, haben wir beide Kandidaten mit identischen Prototypen als GraalVM Native Image gebaut und vermessen.
Die Messwerte und die Erkenntnisse aus dem Vergleich stellen wir in diesem Beitrag vor.
Dank der Java GraalVM in Kombination mit dem Werkzeug native-image lassen sich Java Anwendungen in nativ kompilierte Binaries überführen, die sogar statisch gelinkt sein können.
Damit entfällt die Initialisierung der HotSpot VM sowie das Laden und Initialisieren von Klassen.
Eine derartig gebaute Java Anwendung lässt sich in sehr kurzer Zeit starten.
Selbst mit umfangreichen Abhängigkeiten wie Thymeleaf und Spring Security kann man hier im Bereich von einer Sekunde den vollständigen Anwendungsstart erwarten.
Dazu kommt ein gut vorhersagbarer Speicherverbrauch zur Laufzeit, der zudem auch geringer ausfällt als bei der sehr dynamischen HotSpot VM.
Der Tradeoff von GraalVM-Native-Anwendungen ist, dass die Peakperformance im Vergleich zu HotSpot geringer ausfällt und Oracle zudem bestimmte Performanceoptimierungen nur in einer kommerziellen Variante anbietet.
Wie verhält sich Spring Boot mit Spring native - derzeit in Version 0.11.1 als beta - in Bezug auf den produktiven Einsatz?
Worauf gilt es zu achten und was funktioniert nicht, wie man es erwartet?
Diese Aspekte werden im Folgenden betrachtet.
Java Anwendungen haben den Ruf, schwergewichtig und langsam zu sein.
Langsam ist Java dank ausgefeilter Optimierungen der JVM zwar nicht (mehr), jedoch sind Docker Container Images von Anwendungen relativ groß.
Das ist dadurch bedingt, dass eine JVM und ein Betriebssystem mitgeliefert werden müssen, damit die Java Anwendung im Docker Container ausgeführt werden kann.
In aktuellen Java Versionen ist dank GraalVM die Möglichkeit gegeben, Java Anwendungen als native Programme zu kompilieren und statisch zu linken.
Damit ist weder eine JVM noch ein Betriebssystem im Container Image erforderlich - vergleichbar mit dem aus der Go Welt bekannten Vorgehen.
Wie das Ganze funktioniert, wird im folgenden Beitrag vorgestellt.