Il lin­guag­gio di pro­gram­ma­zio­ne Java è con­si­de­ra­to il “veterano dell’industria IT”. È stato creato nei primi anni di Internet ma il web si è svi­lup­pa­to molto ra­pi­da­men­te da allora. Oltre alla classica ar­chi­tet­tu­ra client-server, esiste una serie di modelli al­ter­na­ti­vi in­te­res­san­ti: ap­pli­ca­zio­ni basate su container, mi­cro­ser­vi­zi, ser­ver­less computing e web app reattive si sono ra­pi­da­men­te diffuse e affermate. Questi tipi di ap­pli­ca­zio­ni sono stati finora difficili da im­ple­men­ta­re con Java ma, grazie al framework Quarkus, la si­tua­zio­ne è cambiata. Il manager di RedHat, Ken Johnson, lo descrive come segue:

Citazione

“… it’s a very small Java stack, perfect for con­tai­ners, ser­ver­less and other scenarios where you’re running Java ap­pli­ca­tions 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, ser­ver­less e altri scenari in cui vengono eseguite delle ap­pli­ca­zio­ni Java nel cloud”. (Tra­du­zio­ne: IONOS)

In questo articolo, vi pre­sen­te­re­mo Quarkus e vi mo­stre­re­mo come questo framework sta ri­vo­lu­zio­nan­do la creazione delle ap­pli­ca­zio­ni Java.

Cosa rende Quarkus speciale?

Quarkus è un framework svi­lup­pa­to da RedHat per la creazione di ap­pli­ca­zio­ni Java. È stato svi­lup­pa­to con l’obiettivo di eseguire programmi Java in ambienti di container. In par­ti­co­la­re, il framework si concentra sul supporto del software di or­che­stra­zio­ne Ku­ber­ne­tes. Un altro punto focale dello sviluppo di Quarkus è l’uso di librerie e standard Java con­so­li­da­ti.

“HotSpot”, dal progetto OpenJDK, è usato come Java Virtual Machine (JVM) per essere il livello di ese­cu­zio­ne del codice Java. Inoltre, può essere uti­liz­za­to anche lo sviluppo “GraalVM”, che si basa su HotSpot. Quest’ultimo permette al codice Java di essere compilato in un codice macchina di­ret­ta­men­te ese­gui­bi­le. Per capire il vantaggio immediato dell’uso di Quarkus, diamo prima un’occhiata a come le ap­pli­ca­zio­ni Java vengono eseguite con e senza Quarkus.

Come sono state eseguite tra­di­zio­nal­men­te le ap­pli­ca­zio­ni Java?

L’idea di base che ha reso Java ri­vo­lu­zio­na­rio quando è stato in­tro­dot­to era tanto semplice quanto ac­cat­ti­van­te: Java avrebbe reso possibile scrivere un programma senza essere vincolato a un hardware o un sistema operativo specifico. Questa in­di­pen­den­za dalla piat­ta­for­ma è spesso riassunta dalla frase “write once, run anywhere” (“scrivi una volta, esegui ovunque”). La por­ta­bi­li­tà associata permette di spostare il programma da una piat­ta­for­ma all’altra. Senz’altro un’ottima ca­rat­te­ri­sti­ca, ma come funziona?

Come per altri linguaggi di pro­gram­ma­zio­ne, un programma Java inizia con un codice sorgente che può essere letto dall’occhio umano. Per eseguire le istru­zio­ni del codice sorgente su un computer, vengono generate le istru­zio­ni cor­ri­spon­den­ti nel formato del pro­ces­so­re specifico. Con Java, c’è un altro passaggio in­ter­me­dio: il codice sorgente viene prima tradotto in un formato in­ter­me­dio, il co­sid­det­to bytecode, come nel caso del lin­guag­gio Python. Il bytecode viene poi eseguito nella “macchina virtuale Java” (JVM). Per eseguire un programma Java su un di­spo­si­ti­vo, una JVM deve essere in­stal­la­ta su di esso.

Il bytecode è tra­di­zio­nal­men­te in­ter­pre­ta­to per l’ese­cu­zio­ne nella JVM. Le istru­zio­ni bytecode vengono tradotte pezzo per pezzo in istru­zio­ni di codice macchina ed eseguite. Il processo di “com­pi­la­zio­ne just-in-time” (JIT) è più efficace. Con questo processo, anche il bytecode viene con­ver­ti­to in codice macchina, ma entrano in gioco anche ulteriori ot­ti­miz­za­zio­ni. In sintesi, l’ese­cu­zio­ne di un programma Java comporta i seguenti passi:

  1. Com­pi­la­zio­ne del codice sorgente Java in bytecode con il comando del com­pi­la­to­re Java ‘javac’:
javac java_program.java
  1. Ese­cu­zio­ne 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 tec­no­lo­gia per vir­tua­liz­za­re un sistema operativo. Invece, il termine indica il pro­ce­di­men­to per il quale il codice in­ter­me­dio 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 ab­ba­stan­za si­gni­fi­ca­ti­vo. Da un lato, è ne­ces­sa­ria una certa quantità di tempo per avviare la JVM, che si aggiunge al tempo di ese­cu­zio­ne dell’ap­pli­ca­zio­ne attuale. Dall’altro, oltre al maggior consumo di memoria, vi è una perdita di pre­sta­zio­ni. Tutto questo gioca un ruolo minore nelle ap­pli­ca­zio­ni che vengono eseguite per un lungo periodo. Tuttavia, l’approccio non è molto adatto per ap­pli­ca­zio­ni di breve durata basate su container. Ideal­men­te, queste do­vreb­be­ro iniziare il prima possibile. Un tempo di avvio di alcuni secondi è inac­cet­ta­bi­le.

Come vengono eseguite le ap­pli­ca­zio­ni Java con Quarkus?

Al contrario dell’ese­cu­zio­ne nativa delle ap­pli­ca­zio­ni Java, Quarkus offre diversi vantaggi. Si possono di­stin­gue­re due modalità sup­por­ta­te da Quarkus:

  1. Ot­ti­miz­za­zio­ne del bytecode e dell’ese­cu­zio­ne nella JVM
  2. Ese­cu­zio­ne come codice nativo dopo la com­pi­la­zio­ne

Il codice Java scritto con Quarkus può essere eseguito nor­mal­men­te nella JVM. Tuttavia, vi sono notevoli vantaggi in termini di consumo di memoria e tempo di avvio di un’ap­pli­ca­zio­ne in ese­cu­zio­ne. Per ottenere questo, Quarkus usa alcuni trucchi. In par­ti­co­la­re, un certo numero di passaggi che ri­chie­do­no tempo vengono spostati dall’ese­cu­zio­ne al processo di com­pi­la­zio­ne. Questo include i passaggi che al­tri­men­ti si ve­ri­fi­ca­no ogni volta che un’ap­pli­ca­zio­ne Java viene eseguita, come:

  • Caricare e ana­liz­za­re le con­fi­gu­ra­zio­ni
  • Scansione del percorso delle classi Java e ri­so­lu­zio­ne delle an­no­ta­zio­ni
  • Creazione di modelli di entità per database o simili, ove ap­pli­ca­bi­le

Con Quarkus, questi passaggi vengono eseguiti una volta e i risultati vengono me­mo­riz­za­ti nella cache per un recupero rapido. Un’ulteriore ot­ti­miz­za­zio­ne delle pre­sta­zio­ni è data dal fatto che Quarkus riduce la quantità di in­for­ma­zio­ni dinamiche di­spo­ni­bi­li in fase di ese­cu­zio­ne. Queste sono so­sti­tui­te da cor­ri­spon­den­ti costrutti statici, il che è par­ti­co­lar­men­te utile per quanto riguarda l’uso nei container. Un’ap­pli­ca­zio­ne con­tai­ne­riz­za­ta di solito non viene comunque cambiata ed è eseguita sempre nello stesso ambiente.

La seconda modalità sup­por­ta­ta da Quarkus per eseguire ap­pli­ca­zio­ni Java è ancora più in­te­res­san­te. Con la “com­pi­la­zio­ne ahead-of-time” (AOT), il codice macchina di­ret­ta­men­te ese­gui­bi­le viene generato dal codice sorgente Java invece che dal bytecode, il che significa che non c’è più bisogno di una JVM sull’hardware di de­sti­na­zio­ne. Il programma funziona solo su una specifica ar­chi­tet­tu­ra di pro­ces­so­re e deve essere ri­com­pi­la­to per altre piat­ta­for­me. Tuttavia, questa re­stri­zio­ne è di solito ir­ri­le­van­te per l’uso su container. I risparmi nel consumo di memoria e nel tempo di avvio dell’ap­pli­ca­zio­ne ottenuti con la com­pi­la­zio­ne AOT sono a dir poco straor­di­na­ri. Di seguito vi mostriamo un confronto tra i benchmark delle pre­sta­zio­ni, riprese dal sito ufficiale di Quarkus:

Ap­pli­ca­zio­ne 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 ter­mi­no­lo­gia: REST sta a indicare che solo un server web è in ese­cu­zio­ne nel container. Nello scenario REST + CRUD, un database è in ese­cu­zio­ne allo stesso tempo del server web. Per il cloud native stack, il container contiene una JVM, oltre all’ap­pli­ca­zio­ne Java.

Per cosa viene uti­liz­za­to Quarkus?

Quarkus non è solo un altro framework per ap­pli­ca­zio­ni. Infatti, il software è destinato a ri­de­fi­ni­re ciò che significa svi­lup­pa­re delle ap­pli­ca­zio­ni su Java. Ricordate che tra­di­zio­nal­men­te, era più im­por­tan­te che un’ap­pli­ca­zio­ne Java fun­zio­nas­se in modo stabile per molto tempo. Quanto tempo l’ap­pli­ca­zio­ne im­pie­gas­se per avviarsi non era con­si­de­ra­to un fattore critico.

Con­si­de­ra­te ora le ap­pli­ca­zio­ni basate su container: i nuovi container possono essere avviati au­to­ma­ti­ca­men­te dal software di or­che­stra­zio­ne. L’ap­pli­ca­zio­ne nel container dovrebbe quindi essere pronta per l’uso immediato. Inoltre, diversi container ri­don­dan­ti sono spesso avviati per un servizio. Di con­se­guen­za, la riduzione del consumo di risorse ottenuta con Quarkus viene mol­ti­pli­ca­ta.

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

Citazione

“When you think of ser­ver­less computing, mi­cro­ser­vi­ces 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 cor­po­ra­tions that need to keep a single ap­pli­ca­tion up and running for years at a time.”

– Alex Handy, fonte: https://the­new­stack.io/quarkus-gives-spring-boot-users-a-path-to-ser­ver­less-and-live-coding/

“Quando pensate al ser­ver­less computing, ai mi­cro­ser­vi­zi e al [...] cloud, c’è un lin­guag­gio a cui pro­ba­bil­men­te non state [pensando]: Java. E questo è un vero peccato. [...] Java era ed è il lin­guag­gio di lavoro del business. È il terzo lin­guag­gio più popolare al mondo [...] È stato il lin­guag­gio scelto dalle aziende che hanno bisogno di mantenere una singola ap­pli­ca­zio­ne attiva e fun­zio­nan­te per anni”. (Tra­du­zio­ne: IONOS)

I vantaggi di Quarkus sono evidenti. Tuttavia, il framework ha anche alcune li­mi­ta­zio­ni. Quarkus non è destinato, so­prat­tut­to, a essere esportato dalle ap­pli­ca­zio­ni Java esistenti ma vale la pena usarlo come punto di partenza per un nuovo sviluppo. Di seguito trat­te­re­mo alcune aree spe­ci­fi­che di ap­pli­ca­zio­ne. In tutti gli esempi men­zio­na­ti, Maven o Gradle è usato come strumento di com­pi­la­zio­ne. L’area di ap­pli­ca­zio­ne è de­ter­mi­na­ta at­tra­ver­so la con­fi­gu­ra­zio­ne del comando ‘mvn’ o ‘gradle’. Lo strumento di com­pi­la­zio­ne genera quindi au­to­ma­ti­ca­men­te le con­fi­gu­ra­zio­ni e gli artefatti richiesti.

Ese­cu­zio­ne di ap­pli­ca­zio­ni basate su mi­cro­ser­vi­zi su Ku­ber­ne­tes con Java e Quarkus

Ku­ber­ne­tes è un software di or­che­stra­zio­ne per ap­pli­ca­zio­ni container. L’uso di Ku­ber­ne­tes con container Docker è ab­ba­stan­za comune. I singoli servizi di un’ap­pli­ca­zio­ne vengono salvati come immagini Docker e gestiti da Ku­ber­ne­tes. L’or­che­stra­to­re si occupa della gestione dei container generati dalle immagini: Ku­ber­ne­tes avvia, controlla e monitora i servizi. Spesso, vengono avviate più copie di un servizio per la con­di­vi­sio­ne del carico e una maggiore tol­le­ran­za 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 con­fi­gu­ra­zio­ni ne­ces­sa­rie per l’uso su Ku­ber­ne­tes.

Im­ple­men­ta­zio­ne di API REST e ap­pli­ca­zio­ni ser­ver­less con Java e Quarkus

REST è lo stile di ar­chi­tet­tu­ra con­so­li­da­to da tempo per le ap­pli­ca­zio­ni web. Le API in par­ti­co­la­re sono per lo più im­ple­men­ta­te seguendo questo approccio. Un’API REST è basata sull’ar­chi­tet­tu­ra client-server. La co­mu­ni­ca­zio­ne avviene tramite il pro­to­col­lo HTTP usando i “verbi” GET, POST, PUT, DELETE, cor­ri­spon­den­ti ai ben noti “verbi” CRUD (“creare, leggere, ag­gior­na­re, can­cel­la­re”) dell’ambiente database. Lo scambio di dati tra un’API e un utente avviene di solito tramite JSON.

Il ser­ver­less computing è un’ar­chi­tet­tu­ra al­ter­na­ti­va per le ap­pli­ca­zio­ni basate sul cloud. In questo modello, noto anche come “Function as a Service” (FaaS), una singola funzione viene eseguita bre­ve­men­te in un container. La funzione viene ri­chia­ma­ta, esegue un calcolo e poi viene spenta di nuovo. No­no­stan­te il nome, le funzioni ser­ver­less con­ti­nua­no a fun­zio­na­re sui server ma i pro­gram­ma­to­ri non devono più oc­cu­par­se­ne. Inoltre, con AWS Lambda, Google Cloud Functions e Microsoft Azure Functions, gli ambienti ser­ver­less sono di­spo­ni­bi­li su tutte le prin­ci­pa­li piat­ta­for­me cloud e il codice Java può essere uti­liz­za­to su queste piat­ta­for­me tramite Quarkus.

Consiglio

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

Creare ap­pli­ca­zio­ni web reattive con Java e Quarkus

Con­tra­ria­men­te alla pro­gram­ma­zio­ne im­pe­ra­ti­va, la pro­gram­ma­zio­ne reattiva rap­pre­sen­ta un paradigma di pro­gram­ma­zio­ne moderno. Le azioni che do­vreb­be­ro avere luogo quando si ve­ri­fi­ca­no de­ter­mi­na­ti eventi sono descritte da un pro­gram­ma­to­re. I rap­pre­sen­tan­ti più noti di questo stile di pro­gram­ma­zio­ne sono i framework “React” e “Vue”, scritti in Ja­va­Script. Entrambi si con­cen­tra­no sulla creazione di in­ter­fac­ce utente basate sul web. Con Quarkus, le ap­pli­ca­zio­ni possono essere im­ple­men­ta­te in uno stile im­pe­ra­ti­vo e reattivo ed è anche possibile combinare entrambi i paradigmi.

Dov’è uti­liz­za­to Quarkus?

Quarkus è stato pro­get­ta­to con lo scopo di ot­ti­miz­za­re le ap­pli­ca­zio­ni Java per l’uso in ambienti container e cloud. La pos­si­bi­li­tà di compilare un programma Java di­ret­ta­men­te in codice macchina, tuttavia, apre pos­si­bi­li­tà di ap­pli­ca­zio­ne ancora più in­te­res­san­ti. Diamo un’occhiata alle attuali aree di ap­pli­ca­zio­ne più in­te­res­san­ti per Quarkus.

Per prima cosa, ri­cor­dia­mo come viene eseguito un programma Java svi­lup­pa­to con Quarkus. Durante il processo di com­pi­la­zio­ne, 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 in­ter­pre­ta­zio­ne o com­pi­la­zio­ne just-in-time (JIT). A seconda della con­fi­gu­ra­zio­ne, entrano in gioco varie ot­ti­miz­za­zio­ni rilevanti per le pre­sta­zio­ni.

D’altra parte, GraalVM, basato su HotSpot, può essere usato per generare un’immagine nativa usando la com­pi­la­zio­ne AOT (ahead-of-time). L’immagine nativa è un file binario che contiene tutte le librerie e le di­pen­den­ze ne­ces­sa­rie per eseguire l’ap­pli­ca­zio­ne. Poiché nessuna JVM è richiesta per l’ese­cu­zio­ne, i mi­glio­ra­men­ti maggiori delle pre­sta­zio­ni sono ottenuti dalla com­pi­la­zio­ne AOT.

Ap­pli­ca­zio­ni Java in ambienti container

Ku­ber­ne­tes è so­li­ta­men­te coinvolto quando si usa un’app Java in container. Un’app Java im­pac­chet­ta­ta come immagine Docker può anche essere usata su un cluster OpenShift. L’uso di Quarkus con Ku­ber­ne­tes può anche essere testato da voi, ad esempio, usando un’in­stal­la­zio­ne di minikube sul vostro sistema locale.

Funzioni Java in ambienti ser­ver­less

Usa Quarkus per im­ple­men­ta­re fa­cil­men­te una funzione scritta su Java in degli ambienti ser­ver­less di Amazon, Google e Microsoft.

Programmi Java su sistemi embedded

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

Consiglio

Uti­liz­za­te Managed Ku­ber­ne­tes di IONOS per le vostre ap­pli­ca­zio­ni container.

Un confronto tra Quarkus e gli altri framework

Quarkus è adatto a una vasta gamma di scenari ap­pli­ca­ti­vi diversi, tuttavia, altri framework possono essere più specifici. Vediamo un paio di al­ter­na­ti­ve simili:

  • React: questo framework Ja­va­Script si è affermato come lo standard per l’omonima pro­gram­ma­zio­ne reattiva.
  • Open Liberty: questo framework di IBM permette anche lo sviluppo di ap­pli­ca­zio­ni basate su mi­cro­ser­vi­zi tramite Java. Come Quarkus, Open Liberty è dotato di una fun­zio­na­li­tà di live reload.
  • Micronaut: con il framework Micronaut, mi­cro­ser­vi­zi e ap­pli­ca­zio­ni ser­ver­less possono essere pro­gram­ma­ti in Java. Come con Quarkus, anche qui si usa GraalVM.
  • Spring/Spring Boot: Spring è pro­ba­bil­men­te il framework Java più popolare per le ap­pli­ca­zio­ni web. È basato su GraalVM e, oltre alla creazione di mi­cro­ser­vi­zi, supporta la pro­gram­ma­zio­ne reattiva e il live reload. In un confronto di pre­sta­zio­ni, Quarkus batte Spring. Infatti, un progetto Spring esistente può essere esportato su Quarkus in modo re­la­ti­va­men­te facile.

Quali sono i pro e i contro di Quarkus?

Il vantaggio prin­ci­pa­le dello sviluppo di ap­pli­ca­zio­ni Java con Quarkus è un mi­glio­ra­men­to delle pre­sta­zio­ni, il che è par­ti­co­lar­men­te im­por­tan­te quando si usano ap­pli­ca­zio­ni Java in ambienti container. I benefici delle pre­sta­zio­ni includono:

  • Tempo di avvio veloce dell’ap­pli­ca­zio­ne
  • Basso consumo di memoria da parte dell’ap­pli­ca­zio­ne in ese­cu­zio­ne
  • Sca­la­bi­li­tà quasi immediata dei servizi
  • Minori requisiti di spazio per le immagini native

Oltre ai vantaggi in termini di pre­sta­zio­ni, Quarkus brilla so­prat­tut­to per la sua facilità d’uso. Gli svi­lup­pa­to­ri Java EE e Spring esperti possono fa­cil­men­te imparare a usare il framework, be­ne­fi­cia­no anche della struttura solida su cui Quarkus è basato. Tra le altre, vengono uti­liz­za­te le seguenti tec­no­lo­gie standard:

  • Eclipse Mi­cro­Pro­fi­le
  • Spring De­pen­den­cy Injection
  • Hibernate ORM

Quarkus offre anche un ambiente di codifica live, in cui agli svi­lup­pa­to­ri è permesso creare dei prototipi ra­pi­da­men­te. La ca­rat­te­ri­sti­ca del live reload con­tri­bui­sce a uno sviluppo senza intoppi: dopo aver attivato la modalità dev, le modifiche al codice sorgente e alla con­fi­gu­ra­zio­ne vengono compilate in back­ground. Lo svi­lup­pa­to­re deve solo ri­ca­ri­ca­re la finestra del browser per prenderne atto.

Infine, con­clu­de­re­mo con gli svantaggi dell’uso di Quarkus. Questi derivano prin­ci­pal­men­te dalle ot­ti­miz­za­zio­ni che entrano in gioco durante la com­pi­la­zio­ne.

  • In par­ti­co­la­re, ridurre le in­for­ma­zio­ni dinamiche generate durante l’ese­cu­zio­ne può portare a problemi in alcuni scenari.
  • Le pos­si­bi­li­tà for­te­men­te limitate per l’in­tro­spe­zio­ne possono rendere difficile il debug di un’ap­pli­ca­zio­ne.
  • Il processo di com­pi­la­zio­ne altamente ot­ti­miz­za­to per le immagini native richiede molto tempo.

Quarkus non è inteso per qualsiasi progetto Java. Infatti, l’utilizzo di questo framework richiede, in parte, la con­ver­sio­ne dei processi.

Vai al menu prin­ci­pa­le