Hej alla! Här är det andra inlägget i vår serie om Quarkus – idag pratar vi om native kompilering.

– är ett Java-stack som är inriktat på . Och även om det fortfarande finns mycket kvar att göra här, har vi noggrant arbetat med många aspekter, inklusive JVM-optimering och en rad ramverk. En av Quarkus särskilda egenskaper, som har väckt stort intresse hos utvecklare, är den sömlösa och omfattande ansatsen att omvandla Java-kod till körbara filer för specifika operativsystem (den så kallade "native kompileringen") på liknande sätt som C och C++, där sådan kompilering vanligtvis sker i slutet av en cykel som omfattar byggande, testning och distribution.
Och även om native kompilering, som vi kommer att visa nedan, är viktigt, måste det påpekas att Quarkus faktiskt fungerar mycket bra även på en vanlig Java-maskin OpenJDK Hotspot tack vare de prestandaförbättringar vi har fått till stånd i hela stacken. Därför bör native kompilering betraktas som en extra bonus som kan användas vid behov. När det kommer till native bilder förlitar sig Quarkus i stor utsträckning på OpenJDK. Den väl mottagna utvecklingsläget (dev mode) möjliggör nästan omedelbar testning av förändringar tack vare de avancerade funktionerna för dynamisk kodkörning som implementeras i Hotspot. Dessutom används OpenJDK:s klassbibliotek och HotSpot-funktioner vid skapandet av native bilder med GraalVM.
Så varför behövs då native kompilering om allt redan är så bra optimerat? Den frågan ska vi försöka besvara nedan.
Vi börjar med det uppenbara: Red Hat har stor erfarenhet av att optimera JVM, stackar och ramverk under projektets utveckling , inklusive:
- Den första applikationsservern för att arbeta i molnet på plattformen .
- Den första applikationsservern för att arbeta på datorer .
- Den första applikationsservern för att arbeta på .
- Ett antal projekt som arbetar på enheter .
Vi har under många år arbetat med att köra Java-applikationer i molnet och på enheter med begränsade resurser (läs, IoT) och har lärt oss att få ut det mesta av JVM i fråga om prestanda och minnesoptimering. Precis som många andra har vi länge arbetat med native kompilering av Java-applikationer genom , , och även och vi är fullt medvetna om fördelarna och nackdelarna med denna metod (till exempel dilemmat mellan mångsidigheten i "build once – run-anywhere" och det faktum att kompilering av applikationer ger mindre storlek och snabbare uppstart).
Varför är det så viktigt att ta hänsyn till dessa fördelar och nackdelar? För att i vissa situationer kan deras förhållande bli avgörande:
- Till exempel i serverless-/eventdrivna miljöer där i (hård eller mjuk) realtid för att kunna reagera på händelser. Till skillnad från långlivade persistenta tjänster innebär här längden på kallstarten en kritisk ökning av svarstiden på begäran. Att starta JVM tar fortfarande en betydande tid, och även om den i vissa fall kan förkortas med hjälp av rena hårdvarumetoder, kan skillnaden mellan en sekund och 5 millisekunder vara en fråga om liv och död. Ja, här kan man experimentera med att skapa en varm reserv av Java-maskiner (vilket vi till exempel gjorde vid ), men detta garanterar i sig inte tillräckligt med JVM för att hantera begärningar när belastningen ökar. Och ur ett ekonomiskt perspektiv är det förmodligen inte den mest optimala lösningen.
- Dessutom finns det en annan aspekt som ofta dyker upp, nämligen multitenancy. Även om JVM har kommit nära operativsystemens kapabiliteter, är de fortfarande inte kapabla att göra det som vi är så vana vid i Linux - att isolera processer. Därför kan ett fel i en tråd stänga ner hela Java-maskinen. Många försöker kringgå denna brist genom att tilldela varje användares applikation en separat JVM för att minimera konsekvenserna av ett fel. Detta är helt logiskt, men passar dåligt med skalning.
- Dessutom är en viktig faktor för molnbaserade applikationer densiteten av tjänster på värden. Övergången till metodologin , mikrotjänster och Kubernetes ökar antalet Java-maskiner för en applikation. Det innebär att å ena sidan ger allt detta flexibilitet och pålitlighet, men samtidigt ökar också den basminnesförbrukningen per tjänst, där vissa av dessa kostnader långt ifrån alltid är absolut nödvändiga. Statiskt kompilerade körfiler vinner här genom olika optimeringstekniker, som låg-nivå dead-code elimination, där endast de delar av ramverken (inklusive själva JDK) som tjänsten faktiskt använder inkluderas i den slutliga bilden. Därför hjälper den inbyggda kompileringen av Quarkus att mer effektivt placera tjänstinstanser på värden utan att det påverkar säkerheten.
De ovan nämnda argumenten är redan tillräckliga för att förstå rättfärdigheten av inbyggd kompilering ur perspektivet för deltagarna i Quarkus-projektet. Men det finns en annan, inte-teknisk, men också viktig anledning: under de senaste åren har många programmerare och utvecklingsföretag övergett Java till förmån för nya programmeringsspråk, ansett att Java med sina JVM:er, stackar och ramverk har blivit för minneskrävande, för långsam, osv.
Men vanan att använda samma verktyg för att lösa alla uppgifter – . Ibland är det bättre att ta ett steg tillbaka och leta efter något annat. Och om Quarkus får människor att pausa och tänka efter, så är det bra för hela Java-ekosystemet. Quarkus representerar en innovativ syn på hur man skapar effektivare applikationer och gör Java mer relevant för nya applikationsarkitekturer, som serverlös. Dessutom, tack vare sin utbyggbarhet, hoppas vi att Quarkus kommer att få ett helt ekosystem av Java-tillägg, vilket avsevärt ökar antalet ramverk som kommer att stödja inbyggd kompilering som en del av applikationerna.
Källa: habr.com
