Cos’è Quarkus?

Il linguaggio di programmazione Java è considerato il “veterano dell’industria IT”. È stato creato nei primi anni di Internet ma il web si è sviluppato molto rapidamente da allora. Oltre alla classica architettura client-server, esiste una serie di modelli alternativi interessanti: applicazioni basate su container, microservizi, serverless computing e web app reattive si sono rapidamente diffuse e affermate. Questi tipi di applicazioni sono stati finora difficili da implementare con Java ma, grazie al framework Quarkus, la situazione è cambiata. Il manager di RedHat, Ken Johnson, lo descrive come segue:

Citazione

“… it’s a very small Java stack, perfect for containers, serverless and other scenarios where you’re running Java applications in the cloud.”

– Ken Johnson, fonte: https://www.openshift.com/blog/quarkus-is-here-for-your-java

“... è uno stack Java molto piccolo, perfetto per container, serverless e altri scenari in cui vengono eseguite delle applicazioni Java nel cloud”. (Traduzione: IONOS)

In questo articolo, vi presenteremo Quarkus e vi mostreremo come questo framework sta rivoluzionando la creazione delle applicazioni Java.

Cosa rende Quarkus speciale?

Quarkus è un framework sviluppato da RedHat per la creazione di applicazioni Java. È stato sviluppato con l’obiettivo di eseguire programmi Java in ambienti di container. In particolare, il framework si concentra sul supporto del software di orchestrazione Kubernetes. Un altro punto focale dello sviluppo di Quarkus è l’uso di librerie e standard Java consolidati.

“HotSpot”, dal progetto OpenJDK, è usato come Java Virtual Machine (JVM) per essere il livello di esecuzione del codice Java. Inoltre, può essere utilizzato anche lo sviluppo “GraalVM”, che si basa su HotSpot. Quest’ultimo permette al codice Java di essere compilato in un codice macchina direttamente eseguibile. Per capire il vantaggio immediato dell’uso di Quarkus, diamo prima un’occhiata a come le applicazioni Java vengono eseguite con e senza Quarkus.

Come sono state eseguite tradizionalmente le applicazioni Java?

L’idea di base che ha reso Java rivoluzionario quando è stato introdotto era tanto semplice quanto accattivante: Java avrebbe reso possibile scrivere un programma senza essere vincolato a un hardware o un sistema operativo specifico. Questa indipendenza dalla piattaforma è spesso riassunta dalla frase “write once, run anywhere” (“scrivi una volta, esegui ovunque”). La portabilità associata permette di spostare il programma da una piattaforma all’altra. Senz’altro un’ottima caratteristica, ma come funziona?

Come per altri linguaggi di programmazione, un programma Java inizia con un codice sorgente che può essere letto dall’occhio umano. Per eseguire le istruzioni del codice sorgente su un computer, vengono generate le istruzioni corrispondenti nel formato del processore specifico. Con Java, c’è un altro passaggio intermedio: il codice sorgente viene prima tradotto in un formato intermedio, il cosiddetto bytecode, come nel caso del linguaggio Python. Il bytecode viene poi eseguito nella “macchina virtuale Java” (JVM). Per eseguire un programma Java su un dispositivo, una JVM deve essere installata su di esso.

Il bytecode è tradizionalmente interpretato per l’esecuzione nella JVM. Le istruzioni bytecode vengono tradotte pezzo per pezzo in istruzioni di codice macchina ed eseguite. Il processo di “compilazione just-in-time” (JIT) è più efficace. Con questo processo, anche il bytecode viene convertito in codice macchina, ma entrano in gioco anche ulteriori ottimizzazioni. In sintesi, l’esecuzione di un programma Java comporta i seguenti passi:

  1. Compilazione del codice sorgente Java in bytecode con il comando del compilatore Java ‘javac’:
javac java_program.java
  1. Esecuzione del bytecode Java con il comando Java di runtime ‘java’. Viene quindi generato il codice macchina:
java java_program
N.B.

In questo caso si parla di una “macchina virtuale”. Anche se il termine è lo stesso, in questo contesto non si riferisce a una tecnologia per virtualizzare un sistema operativo. Invece, il termine indica il procedimento per il quale il codice intermedio viene tradotto in codice macchina.

Per quanto sia pratico il modello Java “scrivi una volta, esegui ovunque”, l’approccio ha alcune debolezze: l’uso della JVM comporta un overhead abbastanza significativo. Da un lato, è necessaria una certa quantità di tempo per avviare la JVM, che si aggiunge al tempo di esecuzione dell’applicazione attuale. Dall’altro, oltre al maggior consumo di memoria, vi è una perdita di prestazioni. Tutto questo gioca un ruolo minore nelle applicazioni che vengono eseguite per un lungo periodo. Tuttavia, l’approccio non è molto adatto per applicazioni di breve durata basate su container. Idealmente, queste dovrebbero iniziare il prima possibile. Un tempo di avvio di alcuni secondi è inaccettabile.

Come vengono eseguite le applicazioni Java con Quarkus?

Al contrario dell’esecuzione nativa delle applicazioni Java, Quarkus offre diversi vantaggi. Si possono distinguere due modalità supportate da Quarkus:

  1. Ottimizzazione del bytecode e dell’esecuzione nella JVM
  2. Esecuzione come codice nativo dopo la compilazione

Il codice Java scritto con Quarkus può essere eseguito normalmente nella JVM. Tuttavia, vi sono notevoli vantaggi in termini di consumo di memoria e tempo di avvio di un’applicazione in esecuzione. Per ottenere questo, Quarkus usa alcuni trucchi. In particolare, un certo numero di passaggi che richiedono tempo vengono spostati dall’esecuzione al processo di compilazione. Questo include i passaggi che altrimenti si verificano ogni volta che un’applicazione Java viene eseguita, come:

  • Caricare e analizzare le configurazioni
  • Scansione del percorso delle classi Java e risoluzione delle annotazioni
  • Creazione di modelli di entità per database o simili, ove applicabile

Con Quarkus, questi passaggi vengono eseguiti una volta e i risultati vengono memorizzati nella cache per un recupero rapido. Un’ulteriore ottimizzazione delle prestazioni è data dal fatto che Quarkus riduce la quantità di informazioni dinamiche disponibili in fase di esecuzione. Queste sono sostituite da corrispondenti costrutti statici, il che è particolarmente utile per quanto riguarda l’uso nei container. Un’applicazione containerizzata di solito non viene comunque cambiata ed è eseguita sempre nello stesso ambiente.

La seconda modalità supportata da Quarkus per eseguire applicazioni Java è ancora più interessante. Con la “compilazione ahead-of-time” (AOT), il codice macchina direttamente eseguibile viene generato dal codice sorgente Java invece che dal bytecode, il che significa che non c’è più bisogno di una JVM sull’hardware di destinazione. Il programma funziona solo su una specifica architettura di processore e deve essere ricompilato per altre piattaforme. Tuttavia, questa restrizione è di solito irrilevante per l’uso su container. I risparmi nel consumo di memoria e nel tempo di avvio dell’applicazione ottenuti con la compilazione AOT sono a dir poco straordinari. Di seguito vi mostriamo un confronto tra i benchmark delle prestazioni, riprese dal sito ufficiale di Quarkus:

Applicazione Scenario Utilizzo memoria Tempo per la prima risposta
Quarkus + AOT REST 12 MB 0,02 s
Quarkus + AOT REST + CRUD 28 MB 0,04 s
Quarkus + JIT REST 73 MB 0,94 s
Quarkus + JIT REST + CRUD 145 MB 2,03 s
Cloud Native Stack REST 136 MB 4,3 s
Cloud Native Stack REST + CRUD 209 MB 9,5 s
N.B.

Per quanto riguarda la terminologia: REST sta a indicare che solo un server web è in esecuzione nel container. Nello scenario REST + CRUD, un database è in esecuzione allo stesso tempo del server web. Per il cloud native stack, il container contiene una JVM, oltre all’applicazione Java.

Per cosa viene utilizzato Quarkus?

Quarkus non è solo un altro framework per applicazioni. Infatti, il software è destinato a ridefinire ciò che significa sviluppare delle applicazioni su Java. Ricordate che tradizionalmente, era più importante che un’applicazione Java funzionasse in modo stabile per molto tempo. Quanto tempo l’applicazione impiegasse per avviarsi non era considerato un fattore critico.

Considerate ora le applicazioni basate su container: i nuovi container possono essere avviati automaticamente dal software di orchestrazione. L’applicazione nel container dovrebbe quindi essere pronta per l’uso immediato. Inoltre, diversi container ridondanti sono spesso avviati per un servizio. Di conseguenza, la riduzione del consumo di risorse ottenuta con Quarkus viene moltiplicata.

Alex Handy, manager di RedHat, riassume il concetto come segue:

Citazione

“When you think of serverless computing, microservices and the […] cloud, there’s one language you’re probably not [thinking of]: Java. And that’s a real shame. […] Java was and is the workhorse language of business. It remains the third most popular language in the world […] It’s been the language of choice for corporations that need to keep a single application up and running for years at a time.”

– Alex Handy, fonte: https://thenewstack.io/quarkus-gives-spring-boot-users-a-path-to-serverless-and-live-coding/

“Quando pensate al serverless computing, ai microservizi e al [...] cloud, c’è un linguaggio a cui probabilmente non state [pensando]: Java. E questo è un vero peccato. [...] Java era ed è il linguaggio di lavoro del business. È il terzo linguaggio più popolare al mondo [...] È stato il linguaggio scelto dalle aziende che hanno bisogno di mantenere una singola applicazione attiva e funzionante per anni”. (Traduzione: IONOS)

I vantaggi di Quarkus sono evidenti. Tuttavia, il framework ha anche alcune limitazioni. Quarkus non è destinato, soprattutto, a essere esportato dalle applicazioni Java esistenti ma vale la pena usarlo come punto di partenza per un nuovo sviluppo. Di seguito tratteremo alcune aree specifiche di applicazione. In tutti gli esempi menzionati, Maven o Gradle è usato come strumento di compilazione. L’area di applicazione è determinata attraverso la configurazione del comando ‘mvn’ o ‘gradle’. Lo strumento di compilazione genera quindi automaticamente le configurazioni e gli artefatti richiesti.

Esecuzione di applicazioni basate su microservizi su Kubernetes con Java e Quarkus

Kubernetes è un software di orchestrazione per applicazioni container. L’uso di Kubernetes con container Docker è abbastanza comune. I singoli servizi di un’applicazione vengono salvati come immagini Docker e gestiti da Kubernetes. L’orchestratore si occupa della gestione dei container generati dalle immagini: Kubernetes avvia, controlla e monitora i servizi. Spesso, vengono avviate più copie di un servizio per la condivisione del carico e una maggiore tolleranza ai guasti. Se uno dei servizi si blocca, il container viene distrutto e un nuovo container viene creato dalla stessa immagine. Quarkus include già di default le configurazioni necessarie per l’uso su Kubernetes.

Implementazione di API REST e applicazioni serverless con Java e Quarkus

REST è lo stile di architettura consolidato da tempo per le applicazioni web. Le API in particolare sono per lo più implementate seguendo questo approccio. Un’API REST è basata sull’architettura client-server. La comunicazione avviene tramite il protocollo HTTP usando i “verbi” GET, POST, PUT, DELETE, corrispondenti ai ben noti “verbi” CRUD (“creare, leggere, aggiornare, cancellare”) dell’ambiente database. Lo scambio di dati tra un’API e un utente avviene di solito tramite JSON.

Il serverless computing è un’architettura alternativa per le applicazioni basate sul cloud. In questo modello, noto anche come “Function as a Service” (FaaS), una singola funzione viene eseguita brevemente in un container. La funzione viene richiamata, esegue un calcolo e poi viene spenta di nuovo. Nonostante il nome, le funzioni serverless continuano a funzionare sui server ma i programmatori non devono più occuparsene. Inoltre, con AWS Lambda, Google Cloud Functions e Microsoft Azure Functions, gli ambienti serverless sono disponibili su tutte le principali piattaforme cloud e il codice Java può essere utilizzato su queste piattaforme tramite Quarkus.

Consiglio

Create la vostra API REST su un server dedicato di IONOS.

Creare applicazioni web reattive con Java e Quarkus

Contrariamente alla programmazione imperativa, la programmazione reattiva rappresenta un paradigma di programmazione moderno. Le azioni che dovrebbero avere luogo quando si verificano determinati eventi sono descritte da un programmatore. I rappresentanti più noti di questo stile di programmazione sono i framework “React” e “Vue”, scritti in JavaScript. Entrambi si concentrano sulla creazione di interfacce utente basate sul web. Con Quarkus, le applicazioni possono essere implementate in uno stile imperativo e reattivo ed è anche possibile combinare entrambi i paradigmi.

Dov’è utilizzato Quarkus?

Quarkus è stato progettato con lo scopo di ottimizzare le applicazioni Java per l’uso in ambienti container e cloud. La possibilità di compilare un programma Java direttamente in codice macchina, tuttavia, apre possibilità di applicazione ancora più interessanti. Diamo un’occhiata alle attuali aree di applicazione più interessanti per Quarkus.

Per prima cosa, ricordiamo come viene eseguito un programma Java sviluppato con Quarkus. Durante il processo di compilazione, il codice sorgente Java viene compilato in bytecode, che viene poi tradotto in codice macchina quando viene eseguito. Il bytecode può essere generato con Quarkus, che viene poi eseguito in un ambiente runtime Java, come la VM HotSpot, tramite interpretazione o compilazione just-in-time (JIT). A seconda della configurazione, entrano in gioco varie ottimizzazioni rilevanti per le prestazioni.

D’altra parte, GraalVM, basato su HotSpot, può essere usato per generare un’immagine nativa usando la compilazione AOT (ahead-of-time). L’immagine nativa è un file binario che contiene tutte le librerie e le dipendenze necessarie per eseguire l’applicazione. Poiché nessuna JVM è richiesta per l’esecuzione, i miglioramenti maggiori delle prestazioni sono ottenuti dalla compilazione AOT.

Applicazioni Java in ambienti container

Kubernetes è solitamente coinvolto quando si usa un’app Java in container. Un’app Java impacchettata come immagine Docker può anche essere usata su un cluster OpenShift. L’uso di Quarkus con Kubernetes può anche essere testato da voi, ad esempio, usando un’installazione di minikube sul vostro sistema locale.

Funzioni Java in ambienti serverless

Usa Quarkus per implementare facilmente una funzione scritta su Java in degli ambienti serverless di Amazon, Google e Microsoft.

Programmi Java su sistemi embedded

Data la capacità di creare un’immagine nativa da un’applicazione Java, il codice Java può essere usato anche nei sistemi embedded. In questo caso entra in gioco la compilazione AOT, che assicura un basso consumo di memoria e dei tempi di avvio rapidi per un’applicazione specifica.

Consiglio

Utilizzate Managed Kubernetes di IONOS per le vostre applicazioni container.

Un confronto tra Quarkus e gli altri framework

Quarkus è adatto a una vasta gamma di scenari applicativi diversi, tuttavia, altri framework possono essere più specifici. Vediamo un paio di alternative simili:

  • React: questo framework JavaScript si è affermato come lo standard per l’omonima programmazione reattiva.
  • Open Liberty: questo framework di IBM permette anche lo sviluppo di applicazioni basate su microservizi tramite Java. Come Quarkus, Open Liberty è dotato di una funzionalità di live reload.
  • Micronaut: con il framework Micronaut, microservizi e applicazioni serverless possono essere programmati in Java. Come con Quarkus, anche qui si usa GraalVM.
  • Spring/Spring Boot: Spring è probabilmente il framework Java più popolare per le applicazioni web. È basato su GraalVM e, oltre alla creazione di microservizi, supporta la programmazione reattiva e il live reload. In un confronto di prestazioni, Quarkus batte Spring. Infatti, un progetto Spring esistente può essere esportato su Quarkus in modo relativamente facile.

Quali sono i pro e i contro di Quarkus?

Il vantaggio principale dello sviluppo di applicazioni Java con Quarkus è un miglioramento delle prestazioni, il che è particolarmente importante quando si usano applicazioni Java in ambienti container. I benefici delle prestazioni includono:

  • Tempo di avvio veloce dell’applicazione
  • Basso consumo di memoria da parte dell’applicazione in esecuzione
  • Scalabilità quasi immediata dei servizi
  • Minori requisiti di spazio per le immagini native

Oltre ai vantaggi in termini di prestazioni, Quarkus brilla soprattutto per la sua facilità d’uso. Gli sviluppatori Java EE e Spring esperti possono facilmente imparare a usare il framework, beneficiano anche della struttura solida su cui Quarkus è basato. Tra le altre, vengono utilizzate le seguenti tecnologie standard:

  • Eclipse MicroProfile
  • Spring Dependency Injection
  • Hibernate ORM

Quarkus offre anche un ambiente di codifica live, in cui agli sviluppatori è permesso creare dei prototipi rapidamente. La caratteristica del live reload contribuisce a uno sviluppo senza intoppi: dopo aver attivato la modalità dev, le modifiche al codice sorgente e alla configurazione vengono compilate in background. Lo sviluppatore deve solo ricaricare la finestra del browser per prenderne atto.

Infine, concluderemo con gli svantaggi dell’uso di Quarkus. Questi derivano principalmente dalle ottimizzazioni che entrano in gioco durante la compilazione.

  • In particolare, ridurre le informazioni dinamiche generate durante l’esecuzione può portare a problemi in alcuni scenari.
  • Le possibilità fortemente limitate per l’introspezione possono rendere difficile il debug di un’applicazione.
  • Il processo di compilazione altamente ottimizzato per le immagini native richiede molto tempo.

Quarkus non è inteso per qualsiasi progetto Java. Infatti, l’utilizzo di questo framework richiede, in parte, la conversione dei processi.

Per offrirti una migliore esperienza di navigazione online questo sito web usa dei cookie, propri e di terze parti. Continuando a navigare sul sito acconsenti all’utilizzo dei cookie. Scopri di più sull’uso dei cookie e sulla possibilità di modificarne le impostazioni o negare il consenso.