Quest'anno abbiamo in programma di sviluppare seriamente i temi dei container, e . Un naturale proseguimento di questi temi sarà il racconto del framework Quarkus, già su Habr. L'articolo di oggi è dedicato non tanto alla struttura della «Java subatomica ultraveloce», quanto alle prospettive che Quarkus porta nel mondo Enterprise.

Java e JVM rimangono estremamente popolari, ma nell'uso di tecnologie serverless e microservizi orientati al cloud, Java e altri linguaggi per la JVM vengono applicati sempre meno, poiché occupano troppo spazio in memoria e si caricano troppo lentamente, rendendoli poco adatti all'uso con container a vita breve. Fortunatamente, questa situazione sta iniziando a cambiare grazie a Quarkus.
La Java subatomica ultraveloce ha raggiunto un nuovo livello!
42 versioni, 8 mesi di lavoro della comunità e 177 sviluppatori straordinari – il risultato di tutto ciò è stato il rilascio nel novembre 2019 di , una versione che segna un'importante pietra miliare nello sviluppo del progetto e offre un sacco di fantastiche funzionalità e possibilità (puoi leggere di più su di esse in ).
Oggi parleremo di come Quarkus unisce i modelli di programmazione imperativa e reattiva basati su un unico nucleo reattivo. Inizieremo con una breve escursione nella storia e poi analizzeremo in dettaglio in cosa consiste il dualismo del nucleo reattivo di Quarkus e come -i programmatori possono trarre vantaggio da questi benefici.
, e -funzioni – tutto ciò oggi è in forte crescita. Recentemente, la creazione di architetture orientate al cloud è diventata molto più semplice e accessibile, ma i problemi rimangono – specialmente per gli sviluppatori Java. Ad esempio, nel caso delle funzioni serverless e dei microservizi c'è un'esigenza urgente di ridurre i tempi di avvio, diminuire il consumo di memoria e rendere la loro sviluppo più comodo e piacevole. Negli ultimi anni, Java ha apportato alcuni miglioramenti, come funzionalità ergonomiche ottimizzate per i container e altro. Tuttavia, ottenere un funzionamento efficace di Java in un container continua a essere una sfida. Pertanto, iniziamo esaminando alcune delle complessità interne di Java che si manifestano in modo particolarmente accentuato durante lo sviluppo di applicazioni Java orientate ai container.
Iniziamo con la storia.

Flussi e container
A partire dalla versione 8u131, Java ha iniziato a supportare in modo più efficace i container grazie a miglioramenti nella funzionalità ergonomics. In particolare, ora la JVM sa su quanti core del processore viene eseguita e può configurare i pool di thread di conseguenza, generalmente usando pool fork/join. Certamente, questo è positivo, ma supponiamo di avere un'applicazione web tradizionale che utilizza servlet HTTP e gira su Tomcat, Jetty e simili. Di conseguenza, questa applicazione assegnerà un thread separato per ogni richiesta, permettendole di bloccare quel thread durante l'attesa delle operazioni di input-output, ad esempio durante l'accesso a database, file o altri servizi. Questo significa che le dimensioni di tale applicazione non dipendono dal numero di core disponibili, ma dal numero di richieste simultanee. Inoltre, ciò implica che le quote o i limiti in Kubernetes relativi al numero di core non saranno di grande aiuto, e alla fine si finirà per affrontare il throttling.
Esaurimento della memoria
I flussi sono memoria. E le limitazioni interne ai container sulla memoria non sono affatto una panacea. Iniziate semplicemente ad aumentare il numero di applicazioni e flussi, e prima o poi vi troverete di fronte a un aumento critico della frequenza dei cambiamenti e, di conseguenza, a una degradazione delle prestazioni. Inoltre, se un'applicazione utilizza tradizionali framework microservizi, si connette a un database, o utilizza una cache, o in qualche modo consuma memoria in modo aggiuntivo, è evidente che avrete bisogno di uno strumento che permetta di guardare dentro la JVM e vedere come gestisce la memoria, senza compromettere la JVM stessa (ad esempio, XX:+UseCGroupMemoryLimitForHeap). Anche se, a partire da Java 9, la JVM ha imparato a riconoscere i cgroups e ad adattarsi di conseguenza, la prenotazione e la gestione della memoria restano affari piuttosto complessi.
Quote e limiti
In Java 11, support for CPU quotas (such as PreferContainerQuotaForCPUCount) was introduced. Kubernetes also provides support for limits and quotas. Yes, all of this makes sense, but if the application exceeds its allocated quota again, we return to the situation where size — as in traditional Java applications — is determined by the number of cores, with a separate thread allocated for each request. This means that the benefits are minimal.
Moreover, using quotas and limits or the scale-out functions of the Kubernetes underlying platform does not solve the problem by itself. We simply end up consuming more resources to address the original issue or eventually lead to resource overconsumption. If this is a high-load system in a public cloud, we almost certainly start using more resources than necessary.
What should we do about all this?
To put it simply, use asynchronous and non-blocking input-output libraries and frameworks like Netty, o Akka. Sono molto più adatti per lavorare nei contenitori grazie alla loro natura reattiva. Grazie all'I/O non bloccante, lo stesso thread può gestire più richieste simultaneamente. Mentre una richiesta attende risultati di I/O, il thread che la gestisce è liberato e può occuparsi di un'altra richiesta. Quando i risultati di I/O finalmente arrivano, la lavorazione della prima richiesta riprende. Alternando la lavorazione delle richieste all'interno dello stesso thread, è possibile ridurre il numero totale di thread e diminuire i consumi di risorse nella gestione delle richieste.
Con l'I/O non bloccante, il numero di core diventa un parametro fondamentale, poiché determina il numero di thread di I/O che possono essere eseguiti in parallelo. Se utilizzato correttamente, questo permette di distribuire in modo efficace il carico tra i core e gestire carichi più elevati con minori risorse.
Come, e questo è tutto?
No, c'è dell'altro. La programmazione reattiva aiuta a utilizzare meglio le risorse, ma ha anche un prezzo. In particolare, sarà necessario riscrivere il codice secondo i principi di non blocco e evitare il blocco dei flussi di input-output. Questo richiede un approccio completamente diverso nello sviluppo e nell'esecuzione. Anche se ci sono molte librerie utili, si tratta comunque di un cambiamento radicale nel modo di pensare.
Innanzitutto, è necessario imparare a scrivere codice che venga eseguito in modo asincrono. Non appena si inizia a utilizzare l'input-output non bloccante, è necessario specificare esplicitamente cosa dovrebbe accadere quando si riceve una risposta a una richiesta. Non è più possibile semplicemente bloccare e aspettare. In cambio, è possibile utilizzare callback, programmazione reattiva o continuation. Ma non è tutto: per utilizzare l'input-output non bloccante, sono necessari anche server e client non bloccanti, e sarebbe preferibile in ogni caso. Per quanto riguarda HTTP, è semplice, ma ci sono anche database, file system e molto altro.
Anche se la reattività totale consente di ottenere il massimo dell'efficienza, questo spostamento può essere difficile da digerire nella pratica. Perciò, la possibilità di combinare codice reattivo e imperativo diventa una condizione necessaria per:
- Usare in modo efficace le risorse nelle aree più cariche del sistema software;
- Utilizzare un codice più semplice nel suo resto.
Presentiamo Quarkus
Ecco il cuore di Quarkus: unire i modelli reattivi e imperativi all'interno di un'unica runtime.
Alla base di Quarkus ci sono Vert.x e Netty, su cui viene costruita una serie di framework e estensioni reattive pensate per assistere gli sviluppatori. Quarkus è progettato per la creazione non solo di microservizi HTTP, ma anche di architetture a eventi. Grazie alla sua natura reattiva, lavora in modo molto efficace con sistemi di messaggistica (Apache Kafka, AMQP, ecc.).
Il segreto sta nel come utilizzare lo stesso motore reattivo sia per il codice imperativo che per quello reattivo.

Quarkus gestisce questo in modo brillante. La scelta tra imperativo e reattivo è chiara: utilizzare un nucleo reattivo per entrambi. Ciò che supporta notevolmente è il codice non bloccante e veloce, che gestisce quasi tutto ciò che attraversa il ciclo degli eventi (event-loop thread, ovvero IO thread). Tuttavia, se hai applicazioni REST classiche o applicazioni lato client, Quarkus ha pronta una model di programmazione imperativa. Ad esempio, il supporto HTTP in Quarkus è costruito utilizzando un motore non bloccante e reattivo (Eclipse Vert.x e Netty). Tutte le richieste HTTP ricevute dalla tua applicazione passano inizialmente attraverso il ciclo degli eventi (IO Thread), e poi vengono inviate a quella parte del codice che gestisce le richieste. A seconda della destinazione, il codice di gestione delle richieste può essere attivato all'interno di un thread separato (il cosiddetto worker thread, utilizzato nel caso di servlet e Jax-RS) o utilizzare il thread di input/output originale (reactive route).

I connettori dei sistemi di trasmissione dei messaggi utilizzano client non bloccanti, che operano sopra il motore Vert.x. Questo consente di inviare, ricevere e elaborare efficacemente i messaggi dai sistemi di tipo messaging middleware.
Sul sito sono stati raccolti diversi buoni tutorial che aiutano a iniziare a lavorare con Quarkus:
Inoltre, abbiamo preparato corsi pratici online per familiarizzare con diversi aspetti della programmazione reattiva; per seguirli basta un browser, non è necessaria alcuna IDE, e nemmeno un computer. È possibile trovare questi corsi .
Risorse utili
- Il sito del progetto Quarkus è –
- Il progetto Quarkus su GitHub è –
- Il Twitter del progetto Quarkus è –
- Il chat del progetto Quarkus è –
- I forum del progetto Quarkus sono – !forum/quarkus-dev
10 video tutorial su Quarkus per orientarsi nel tema
Come viene riportato sul sito , è un stack Java orientato agli oggetti, ottimizzato per GraalVM e OpenJDK HotSpot, costruito con le migliori librerie e standard Java.
Per aiutarvi a comprendere l'argomento, abbiamo selezionato 10 video tutorial che trattano vari aspetti di Quarkus e esempi del suo utilizzo:
1. Introduzione a Quarkus: il framework Java di nuova generazione per Kubernetes
Autori: Thomas Qvarnstrom e Jason Greene
L'obiettivo del progetto Quarkus è creare una piattaforma Java per Kubernetes e ambienti serverless, unendo modelli di programmazione reattivi e imperativi all'interno di un ambiente di esecuzione unico, permettendo agli sviluppatori di variare flessibilmente l'approccio nel lavorare con una vasta gamma di architetture distribuite. Scopri di più nella lezione introduttiva qui sotto.

2. Quarkus: Java subatomica super veloce
Autore: Burr Sutter
Il tutorial video del ciclo di conferenze online DevNation Live mostra come utilizzare Quarkus per ottimizzare applicazioni Java aziendali, API, microservizi e funzioni serverless nell'ambiente Kubernetes/OpenShift, rendendoli molto più piccoli, veloci e scalabili.

3. Quarkus e GraalVM: spingiamo Hibernate a velocità straordinarie e riduciamolo a dimensioni subatomiche
Autore: Sanne Grinovero
Dalla presentazione, scoprirai come è nato Quarkus, come funziona e come consente di rendere le librerie complesse, come Hibernate ORM, compatibili con le immagini native di GraalVM.

4. Impariamo a sviluppare applicazioni serverless
Autore: Marthen Luther
Nel video qui sotto viene mostrato come creare una semplice applicazione Java utilizzando Quarkus e distribuirla come applicazione serverless su Knative.

5. Quarkus: programma con piacere
Autore: Edson Yanaga
Guida video per creare il tuo primo progetto Quarkus, che ti permette di capire perché Quarkus conquista i cuori degli sviluppatori.

6. Java e container: quale sarà il loro futuro insieme
Autore: Mark Little
Questa presentazione presenta la storia di Java e spiega perché Quarkus rappresenta il futuro di Java.

7. Quarkus: Java subatomico super veloce
Autore: Dimitris Andreadis
Panoramica dei vantaggi di Quarkus, riconosciuti dagli sviluppatori: semplicità, velocità estremamente elevate, migliori librerie e standard.

8. Quarkus e sistemi reattivi subatomici
Autore: Clement Escoffier
Grazie all'integrazione con GraalVM, Quarkus offre un'esperienza di sviluppo ultrarapida e un runtime subatomico. L'autore parla dell'aspetto reattivo di Quarkus e di come utilizzarlo per creare applicazioni reattive e applicazioni con streaming di dati.

9. Quarkus e lo sviluppo rapido di applicazioni in Eclipse MicroProfile
Autore: John Clingan
Combinando Eclipse MicroProfile e Quarkus, gli sviluppatori possono creare applicazioni container MicroProfile a piena funzionalità che si avviano in pochi millisecondi. Il video analizza in dettaglio come codificare un'applicazione container MicroProfile per il deployment sulla piattaforma Kubernetes.

10. Java, versione 'Turbo'
Autore: Marcus Biel
L'autore mostra come utilizzare Quarkus per creare contenitori Java super piccoli e super veloci, consentendo un vero e proprio salto in avanti, soprattutto negli ambienti serverless.

Fonte: habr.com
