Hallo zusammen! Hier ist der zweite Beitrag unserer Quarkus-Serie – heute sprechen wir über die native Kompilierung.

– das ist ein Java-Stack, der auf . Auch wenn hier natürlich noch viel zu tun bleibt, haben wir zahlreiche Aspekte gut bearbeitet, einschließlich der Optimierung der JVM und verschiedener Frameworks. Eine der Besonderheiten von Quarkus, die großes Interesse seitens der Entwickler geweckt hat, ist der umfassende nahtlose Ansatz zur Umwandlung von Java-Code in ausführbare Dateien für spezifische Betriebssysteme (das sogenannte „native Kompilierung“), ähnlich wie in C und C++, wo diese Kompilierung normalerweise am Ende eines Zyklus erfolgt, der aus Build, Test und Deployment besteht.
Obwohl die native Kompilierung, wie wir später zeigen werden, wichtig ist, sollte erwähnt werden, dass Quarkus auch auf einer gewöhnlichen Java-Maschine mit OpenJDK Hotspot hervorragend funktioniert, dank der Performance-Verbesserungen, die wir in der gesamten Architektur implementiert haben. Daher ist die native Kompilierung als zusätzlicher Bonus zu betrachten, den man nach Wunsch oder Bedarf nutzen kann. Tatsächlich baut Quarkus in erheblichem Maße auf OpenJDK bei nativen Bildern. Der bei Entwicklern gut angenommene Entwicklermodus ermöglicht nahezu sofortiges Testen von Änderungen durch die erweiterten Möglichkeiten der dynamischen Codeausführung, die in Hotspot implementiert sind. Zudem wird bei der Erstellung von nativen Bildern die Klassenbibliothek von OpenJDK und die Funktionen von HotSpot verwendet.
Warum ist dann die native Kompilierung notwendig, wenn alles bereits ausgezeichnet optimiert ist? Diese Frage wollen wir im Folgenden beantworten.
Beginnen wir mit dem Offensichtlichen: Red Hat verfügt über umfangreiche Erfahrung in der Optimierung von JVM, Stacks und Frameworks während der Entwicklung des Projekts , einschließlich:
- Der erste Anwendungsserver für den Betrieb in der Cloud auf der Plattform .
- Der erste Anwendungsserver für die Arbeit auf PCs .
- Der erste Anwendungsserver für die Arbeit auf .
- Eine Vielzahl von Projekten, die auf Geräten laufen .
Seit vielen Jahren beschäftigen wir uns mit den Herausforderungen der Ausführung von Java-Anwendungen in der Cloud und auf ressourcenbeschränkten Geräten (sprich, IoT) und haben gelernt, das Maximum aus der JVM in Bezug auf Leistung und Speichereffizienz herauszuholen. Wie viele andere arbeiten wir schon lange mit der nativen Kompilierung von Java-Anwendungen über , , und sogar und sind uns der Vor- und Nachteile dieses Ansatzes bewusst (zum Beispiel die Dilemma zwischen der Vielseitigkeit "build once – run anywhere" und der Tatsache, dass kompilierte Anwendungen eine geringere Größe haben und schneller starten).
Warum ist es so wichtig, diese Vor- und Nachteile zu berücksichtigen? Weil ihr Verhältnis in bestimmten Situationen entscheidend wird:
- Zum Beispiel in serverlosen/ereignisgesteuerten Umgebungen, in denen in Echtzeit (hart oder weich), um auf Ereignisse reagieren zu können. Im Gegensatz zu langlebigen, persistierenden Diensten erhöht hier die Dauer des Kaltstarts die Antwortzeit auf Anfragen erheblich. Der Start der JVM benötigt immer noch erhebliche Zeit, und obwohl es in einigen Fällen möglich ist, diese rein hardwareseitig zu reduzieren, kann der Unterschied zwischen einer Sekunde und 5 Millisekunden eine Frage von Leben und Tod sein. Ja, hier kann man mit der Erstellung eines Hot-Swap-Reservoirs von Java-Maschinen experimentieren (was wir zum Beispiel bei ), doch allein das garantiert nicht die ausreichende Anzahl an JVMs zur Verarbeitung der Anfragen, wenn die Last steigt. Aus wirtschaftlicher Sicht ist dies sicherlich auch nicht die beste Option.
- Ein häufig auftretender Aspekt ist die Multitenantfähigkeit. Obwohl JVMs in ihrer Leistung stark an Betriebssysteme herangekommen sind, sind sie immer noch nicht in der Lage, das zu tun, was wir im Linux gewöhnt sind – Prozesse zu isolieren. Daher kann der Ausfall eines Threads die gesamte Java-Maschine zum Stillstand bringen. Viele versuchen, diesen Nachteil zu umgehen, indem sie für jede Anwendung des Benutzers eine separate JVM bereitstellen, um die Auswirkungen eines Ausfalls zu minimieren. Das macht Sinn, ist jedoch schwer mit der Skalierung zu vereinbaren.
- Zudem ist für cloudbasierte Anwendungen ein wichtiger Faktor die Dichte der Dienste auf einem Host. Der Wechsel zu einer Methodik , Mikrodienste und Kubernetes erhöhen die Anzahl der Java-Instances pro Anwendung. Das bedeutet, einerseits bieten sie Flexibilität und Zuverlässigkeit, andererseits steigen jedoch auch die Grundspeicherkosten pro Dienst, wobei ein Teil dieser Kosten oft nicht strikt notwendig ist. Statisch kompilierte Ausführungsdateien profitieren hier von verschiedenen Optimierungstechniken, wie zum Beispiel der low-level Dead-Code-Eliminierung, bei der nur die Teile der Frameworks (einschließlich des JDK), die der Dienst tatsächlich verwendet, in das finale Image aufgenommen werden. Daher trägt die native Kompilierung von Quarkus dazu bei, die Instanzen der Dienste dichter auf dem Host zu platzieren, ohne die Sicherheit zu gefährden.
Die zuvor genannten Argumente sind bereits ausreichend, um die Berechtigung der nativen Kompilierung aus der Sicht der Teilnehmer des Quarkus-Projekts zu verstehen. Es gibt jedoch einen weiteren, nicht-technischen, aber ebenso wichtigen Grund: In den letzten Jahren haben viele Programmierer und Entwicklerfirmen von Java auf neue Programmiersprachen umgeschaltet, da sie der Meinung sind, dass Java zusammen mit ihren JVMs, Stacks und Frameworks zu speicherintensiv und zu langsam geworden ist.
Allerdings ist es nicht immer richtig, das gleiche Werkzeug für alle Aufgaben zu verwenden - . Manchmal ist es besser, einen Schritt zurückzugehen und nach etwas anderem zu suchen. Und wenn Quarkus die Menschen zum Innehalten und Nachdenken bringt, ist das gut für das gesamte Java-Ökosystem. Quarkus verkörpert eine innovative Perspektive darauf, wie man effizientere Anwendungen erstellt und macht Java relevanter für neue Anwendungsarchitekturen wie serverless. Darüber hinaus hoffen wir, dass Quarkus dank seiner Erweiterbarkeit eine ganze Reihe von Java-Erweiterungen hervorbringen wird, die die Anzahl der Frameworks erheblich erhöhen, die sofort native Kompilierung innerhalb von Anwendungen unterstützen.
Quelle: habr.com
