Ciao a tutti! Questo è il secondo post della nostra serie su Quarkus – oggi parleremo della compilazione nativa.

è uno stack Java progettato per . E sebbene ci sia ancora molto lavoro da fare, abbiamo affrontato con successo numerosi aspetti, inclusa l'ottimizzazione della JVM e di diversi framework. Una delle caratteristiche di Quarkus che ha suscitato un particolare interesse tra gli sviluppatori è stato l'approccio seamless e integrato alla trasformazione del codice Java in file eseguibili per un sistema operativo specifico (la cosiddetta "compilazione nativa"), simile a quanto avviene in C e C++, dove questa compilazione di solito avviene alla fine di un ciclo che consiste in build, testing e distribuzione.
Sebbene la compilazione nativa, come mostreremo più avanti, sia importante, è fondamentale notare che Quarkus funziona davvero bene anche su una comune macchina Java OpenJDK Hotspot grazie ai miglioramenti delle prestazioni che abbiamo implementato attraverso l'intero stack. Pertanto, la compilazione nativa dovrebbe essere vista come un bonus aggiuntivo da utilizzare a piacimento o necessità. In effetti, per quanto riguarda le immagini native, Quarkus si basa in larga misura su OpenJDK. Inoltre, il ben accolto modo di sviluppo dev mode offre test di cambiamenti quasi istantanei grazie alle avanzate capacità di esecuzione dinamica del codice implementate in Hotspot. Inoltre, durante la creazione delle immagini native, GraalVM utilizza la libreria di classi OpenJDK e le capacità di HotSpot.
Allora, perché è necessaria la compilazione nativa, se tutto è già ottimizzato alla perfezione? A questa domanda cercheremo di rispondere qui di seguito.
Iniziamo con l'ovvio: Red Hat ha una vasta esperienza nell'ottimizzazione della JVM, degli stack e dei framework durante lo sviluppo del progetto , inclusi:
- Il primo server di applicazioni progettato per operare nel cloud sulla piattaforma .
- Il primo server applicativo per il lavoro sui computer .
- Il primo server applicativo per il lavoro su .
- Una serie di progetti che operano su dispositivi .
Da molti anni affrontiamo le problematiche di esecuzione delle applicazioni Java nel cloud e su dispositivi a risorse limitate (leggi, IoT) e abbiamo imparato a massimizzare le prestazioni e l'ottimizzazione della memoria della JVM. Come molti altri, da tempo lavoriamo con la compilazione nativa delle applicazioni Java tramite , , e anche e siamo perfettamente consapevoli dei vantaggi e svantaggi di questo approccio (ad esempio, il dilemma della scelta tra versatilità "build once – run-anywhere" e il fatto che le applicazioni compilate hanno dimensioni minori e si avviano più rapidamente).
Perché è così importante tenere conto di questi vantaggi e svantaggi? Perché in alcune situazioni il loro rapporto diventa decisivo:
- Ad esempio, in ambienti serverless / gestiti da eventi, dove in modalità (rigida o morbida) tempo reale, per poter reagire tempestivamente agli eventi. A differenza dei servizi persistenti a lungo termine, in questo caso la durata dell'avvio a freddo aumenta drasticamente il tempo di risposta alle richieste. L'avvio della JVM richiede comunque un tempo significativo e, sebbene in alcuni casi questo possa essere ridotto attraverso metodi puramente hardware, la differenza tra un secondo e 5 millisecondi può essere una questione di vita o di morte. Sì, qui è possibile sperimentare con la creazione di un backup caldo di macchine Java (cosa che abbiamo fatto, ad esempio, con ), ma questo da solo non garantisce un numero sufficiente di JVM per elaborare le richieste man mano che il carico aumenta. E dal punto di vista economico, probabilmente non è nemmeno la scelta più corretta.
- Inoltre, c'è un altro aspetto frequentemente discusso, come la multitenanza. Anche se la JVM ha avvicinato molto le sue capacità a quelle dei sistemi operativi, non riesce ancora a fare ciò a cui siamo abituati in Linux: isolare i processi. Pertanto, un crash di un thread può compromettere l'intera macchina Java. Molti cercano di aggirare questo difetto creando una JVM separata per le applicazioni di ogni utente, al fine di ridurre al minimo le conseguenze di un guasto. È una soluzione logica, ma non si adatta bene alla scalabilità.
- Inoltre, per le applicazioni orientate al cloud, è importante un fattore come la densità dei servizi sull'host. La transizione a una metodologia , microservizi e Kubernetes aumentano il numero di macchine Java per applicazione. Da un lato, tutto ciò offre elasticità e affidabilità, ma nello stesso tempo cresce anche il consumo di memoria di base per servizio, parte del quale non è sempre strettamente necessario. I file eseguibili compilati staticamente guadagnano qui grazie a varie tecniche di ottimizzazione, come l'eliminazione del codice morto a basso livello, quando nell'immagine finale vengono incluse solo le parti dei framework (incluso il JDK) che il servizio utilizza realmente. Pertanto, la compilazione nativa di Quarkus aiuta a posizionare più densamente le istanze dei servizi sull'host senza compromettere la sicurezza.
Di fatto, le argomentazioni presentate sopra sono già sufficienti per comprendere la giustificazione della compilazione nativa dal punto di vista dei partecipanti al progetto Quarkus. Tuttavia, c'è un'altra ragione, non tecnica, ma comunque importante: negli ultimi anni, molti programmatori e aziende sviluppatrici hanno abbandonato Java in favore di nuovi linguaggi di programmazione, ritenendo che Java, insieme alle sue JVM, stack e framework, sia diventata troppo affamata di memoria, troppo lenta, ecc.
Tuttavia, l'abitudine di usare lo stesso strumento per risolvere qualsiasi compito – . A volte è meglio fare un passo indietro e cercare qualcosa di diverso. E se Quarkus costringe le persone a fermarsi e riflettere, è un bene per l'intero ecosistema Java. Quarkus rappresenta una visione innovativa su come creare applicazioni più efficienti, rendendo Java più pertinente alle nuove architetture applicative, come quelle serverless. Inoltre, grazie alla sua estensibilità, Quarkus, come speriamo, darà vita a un'intera ecosistema di estensioni Java, aumentando significativamente il numero di framework che supporteranno nativamente la compilazione delle applicazioni.
Fonte: habr.com
