Hello everyone! Here’s the second post in our series on Quarkus – today we’ll talk about native compilation.

– it’s a Java stack focused on . And while there’s still much to be done here, we’ve worked through a lot of aspects, including JVM optimization and various frameworks. One of the features of Quarkus that has sparked keen interest among developers is the comprehensive seamless approach to transforming Java code into executable files for a specific operating system (the so-called 'native compilation'), similar to C and C++, where such compilation typically occurs at the end of a cycle consisting of building, testing, and deploying.
And although native compilation, as we will show below, is important, it should be noted that Quarkus actually works quite well on a standard Java machine using OpenJDK Hotspot, thanks to the performance improvements we’ve implemented throughout the stack. Therefore, native compilation should be considered an additional bonus that can be used at will or necessity. In fact, when it comes to native images, Quarkus significantly relies on OpenJDK. Furthermore, the warmly received development mode provides near-instant testing of changes due to the advanced capabilities of dynamic code execution implemented in Hotspot. Additionally, when creating native images, GraalVM utilizes the OpenJDK class library and HotSpot capabilities.
So why is native compilation necessary if everything is already well optimized? This is the question we will attempt to answer below.
Let’s start with the obvious: Red Hat has extensive experience in optimizing JVMs, stacks, and frameworks throughout the project’s development. , including:
- The first cloud application server on the .
- The first application server for computers .
- The first application server for .
- A whole range of projects running on devices .
For many years, we have been tackling issues related to running Java applications in the cloud and on resource-constrained devices (think IoT) and have learned to squeeze the most out of JVM in terms of performance and memory optimization. Like many others, we have long been working with the native compilation of Java applications through , , og endda og vi er fuldt ud klar over fordele og ulemper ved denne tilgang (for eksempel dilemmaet mellem alsidigheden i "build once – run-anywhere" og det faktum, at de kompilerede applikationer har en mindre størrelse og starter hurtigere).
Hvorfor er det så vigtigt at tage disse fordele og ulemper i betragtning? Fordi forholdet mellem dem i nogle situationer bliver afgørende:
- For eksempel i serverless/ereventstyrende miljøer, hvor i (hårdt eller blødt) realtid for at kunne reagere på hændelser. I modsætning til langtidsaktive vedholdende tjenester øger varigheden af en kold start kritisk svartiden på anmodninger. Der går stadig væsentlig tid til at starte JVM, og selvom det i nogle tilfælde kan forkortes med rent hardwaremetoder, kan forskellen mellem et sekund og 5 millisekunder være et spørgsmål om liv og død. Ja, her kan man eksperimentere med at oprette en varm reserve af Java-maskiner (som vi eksempelvis gjorde ved ), men det garanterer ikke i sig selv et tilstrækkeligt antal JVM'er til at håndtere anmodninger, mens lasten skaleres. Og økonomisk set er det næppe den mest hensigtsmæssige løsning.
- Derudover er der også det ofte fremhævede aspekt som multitenancy. Selvom JVM'er med deres muligheder er kommet tæt på operativsystemerne, er de stadig ikke i stand til at gøre det, som vi er så vant til i Linux – at isolere processer. Derfor kan et nedbrud af en enkelt tråd få hele Java-maskinen til at bryde sammen. Mange forsøger at omgå denne mangel ved at tildele en separat JVM til hver brugers applikation for at minimere konsekvenserne af nedbrud. Det er ganske logisk, men dårligt foreneligt med skalering.
- Desuden er en vigtig måling for cloud-orienterede applikationer tæthed af tjenester på en vært. Overgangen til metodologien , mikrotjenester og Kubernetes øger antallet af Java-instanser pr. applikation. Det betyder, at på den ene side giver det fleksibilitet og pålidelighed, men samtidig vokser også forbruget af grundlæggende hukommelse pr. tjeneste, hvoraf en del af dette forbrug ikke altid er strengt nødvendigt. Statisk kompilerede eksekverbare filer vinder her ved hjælp af forskellige optimeringsteknikker, såsom lavniveau dead-code elimination, hvor kun de dele af rammerne (inklusive selve JDK), som tjenesten faktisk bruger, inkluderes i det endelige billede. Derfor hjælper den native kompilering fra Quarkus med at placere instanser af tjenester tættere på værten uden at gå på kompromis med sikkerheden.
De ovenstående argumenter er allerede tilstrækkelige til at forstå berettigelsen af native kompilering set fra Quarkus-projektets deltageres perspektiv. Men der er også en anden, ikke-teknisk, men stadig vigtig årsag: I de seneste år har mange programmører og udviklingsvirksomheder opgivet Java til fordel for nye programmeringssprog, idet de har betragtet Java sammen med sine JVM'er, stakke og rammer som for krævende i forhold til hukommelse, alt for langsom osv.
Men vanen med at bruge det samme værktøj til at løse alle opgaver – . Nogle gange er det bedre at tage et skridt tilbage og finde noget andet. Og hvis Quarkus får folk til at tage en pause og tænke over det, så er det godt for hele Java-økosystemet. Quarkus repræsenterer en nyskabende tilgang til, hvordan man skaber mere effektive applikationer, hvilket gør Java mere relevant for nye applikationsarkitekturer som serverless. Derudover, takket være sin udvidelsesmulighed, håber vi, at Quarkus vil få et helt Java-økosystem af udvidelser, hvilket betydeligt vil øge antallet af rammer, der fra starten vil støtte native kompilering som en del af applikationerne.
Kilde: habr.com
