Compilazione nativa in Quarkus: perché è importante

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

Compilazione nativa in Quarkus: perché è importante

Quarkù è uno stack Java su misura per kubernetes. Sebbene ci sia sicuramente molto altro da fare qui, abbiamo svolto un ottimo lavoro su molti aspetti, inclusa l'ottimizzazione della JVM e di una serie di framework. Una delle caratteristiche di Quarkus che ha attirato un crescente interesse da parte degli sviluppatori è il suo approccio completo e diretto alla trasformazione del codice Java in file eseguibili per un sistema operativo specifico (la cosiddetta "compilazione nativa"), simile a C e C++, dove tale compilazione di solito si verifica alla fine di un ciclo di creazione, test e distribuzione.

E sebbene la compilazione nativa sia importante, come mostreremo di seguito, va notato che Quarkus funziona molto bene sulla macchina Java più comune, OpenJDK Hotspot, grazie ai miglioramenti delle prestazioni che abbiamo implementato in tutto lo stack. Pertanto, la compilazione nativa dovrebbe essere considerata come un bonus aggiuntivo che può essere utilizzato a piacimento o necessità. In effetti, Quarkus fa molto affidamento su OpenJDK quando si tratta di immagini native. E la modalità dev, accolta calorosamente dagli sviluppatori, garantisce un test quasi istantaneo delle modifiche grazie alle funzionalità avanzate di esecuzione dinamica del codice implementate in Hotspot. Inoltre, durante la creazione di immagini GraalVM native, vengono utilizzate la libreria di classi OpenJDK e le funzionalità HotSpot.

Allora perché hai bisogno della compilazione nativa se tutto è già perfettamente ottimizzato? Cercheremo di rispondere a questa domanda di seguito.

Cominciamo con l'ovvio: Red Hat ha una vasta esperienza nell'ottimizzazione di JVM, stack e framework durante lo sviluppo del progetto JBoss, Compreso:

Da molti anni affrontiamo le sfide legate all'esecuzione di applicazioni Java nel cloud e su dispositivi con risorse limitate (leggi: IoT) e abbiamo imparato a ottenere il massimo dalla JVM in termini di prestazioni e ottimizzazione della memoria. Come molti altri, lavoriamo da molto tempo con la compilazione nativa di applicazioni Java G.C.J., Avian, ExcelsiorJET e anche Dalvik e siamo ben consapevoli dei pro e dei contro di questo approccio (ad esempio, il dilemma di scegliere tra l’universalità del “build once – run-anywhere” e il fatto che le applicazioni compilate sono più piccole e funzionano più velocemente).

Perché è importante considerare questi pro e contro? Perché in alcune situazioni il loro rapporto diventa decisivo:

  • Ad esempio, in ambienti serverless/guidati da eventi dove i servizi devono semplicemente iniziare in tempo reale (hard o soft) per avere tempo di rispondere agli eventi. A differenza dei servizi persistenti di lunga durata, qui la durata di un avvio a freddo aumenta in modo critico il tempo di risposta a una richiesta. La JVM impiega ancora una notevole quantità di tempo per avviarsi e, sebbene in alcuni casi questo possa essere ridotto con metodi puramente hardware, la differenza tra un secondo e 5 millisecondi può fare la differenza tra la vita e la morte. Sì, qui puoi giocare creando una riserva calda di macchine Java (cosa che, ad esempio, abbiamo fatto con porting di OpenWhisk su Knative), ma ciò di per sé non garantisce che ci saranno abbastanza JVM per elaborare le richieste man mano che il carico aumenta. E da un punto di vista economico, questa probabilmente non è l'opzione più corretta.
  • Inoltre, c’è un altro aspetto che emerge spesso: la multitenancy. Nonostante il fatto che le JVM si siano avvicinate molto ai sistemi operativi nelle loro capacità, non sono ancora in grado di fare ciò a cui siamo così abituati in Linux: isolare i processi. Pertanto, il fallimento di un thread può causare il blocco dell'intera macchina Java. Molte persone cercano di aggirare questo inconveniente dedicando una JVM separata per l'applicazione di ciascun utente al fine di ridurre al minimo le conseguenze di un errore. Questo è abbastanza logico, ma non si adatta bene al ridimensionamento.
  • Inoltre, per le applicazioni orientate al cloud, un indicatore importante è la densità dei servizi sull'host. Transizione alla metodologia 12 fattori applicativi, microservizi e Kubernetes aumentano il numero di macchine Java per applicazione. Cioè, da un lato tutto ciò garantisce elasticità e affidabilità, ma allo stesso tempo aumenta anche il consumo di memoria di base in termini di servizio, e alcune di queste spese non sono sempre strettamente necessarie. I file eseguibili compilati staticamente traggono vantaggio qui grazie a varie tecniche di ottimizzazione, come l'eliminazione del codice morto di basso livello, quando l'immagine finale include solo quelle parti del framework (incluso lo stesso JDK) che il servizio effettivamente utilizza. Pertanto, la compilazione nativa di Quarkus aiuta a posizionare in modo denso le istanze del servizio sull'host senza compromettere la sicurezza.

In realtà, gli argomenti di cui 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 anche importante: negli ultimi anni, molti programmatori e società di sviluppo hanno abbandonato Java a favore di nuovi linguaggi di programmazione, ritenendo che Java, insieme alle sue JVM, stack e framework, sia diventato troppo affamato di memoria, troppo lento, ecc.

Tuttavia, l’abitudine di utilizzare lo stesso strumento per risolvere qualsiasi problema lo è non è sempre giusto. A volte è meglio fare un passo indietro e cercare qualcos'altro. E se Quarkus fa riflettere le persone, allora è un bene per l'intero ecosistema Java. Quarkus rappresenta una visione innovativa di come creare applicazioni più efficienti, rendendo Java più rilevante per le nuove architetture applicative come serverless. Inoltre, grazie alla sua estensibilità, si spera che Quarkus disponga di un intero ecosistema di estensioni Java, aumentando in modo significativo il numero di framework che supporteranno la compilazione nativa nelle applicazioni pronte all'uso.

Fonte: habr.com

Aggiungi un commento