Quest'anno prevediamo di sviluppare seriamente i temi dei container, e . Un seguito logico a questi temi sarà la discussione sul framework Quarkus, già su Habr. L'articolo di oggi non si concentra tanto sull'architettura della «Java subatomica superveloce», quanto sulle prospettive che Quarkus porta nel mondo Enterprise.

Java e la JVM sono ancora eccezionalmente popolari, ma quando si tratta di tecnologie serverless e microservizi orientati al cloud, Java e altri linguaggi per la JVM vengono utilizzati sempre meno, in quanto occupano troppo spazio in memoria e si caricano troppo lentamente, risultando quindi poco adatti per essere utilizzati con container a breve durata. Fortunatamente, questa situazione sta iniziando a cambiare grazie a Quarkus.
La Java subatomica superveloce ha raggiunto un nuovo livello!
42 release, 8 mesi di lavoro della comunità e 177 straordinari sviluppatori – il risultato di tutto ciò è stata la pubblicazione nel novembre 2019 di , una release che segna una tappa importante nello sviluppo del progetto e offre molte funzionalità e possibilità interessanti (puoi leggerne di più in ).
Oggi parleremo di come Quarkus unisca i modelli di programmazione imperativa e reattiva su una base di un unico nucleo reattivo. Inizieremo con una breve escursione nella storia, per poi analizzare nei dettagli in cosa consiste il dualismo del nucleo reattivo di Quarkus e come -gli sviluppatori possono sfruttare questi vantaggi.
, e -le funzioni – tutto questo oggi, per così dire, è in crescita. Recentemente, la creazione di architetture orientate al cloud è diventata molto più semplice e accessibile, ma i problemi rimangono, soprattutto per gli sviluppatori Java. Ad esempio, nel caso delle funzioni serverless e dei microservizi, c'è una forte necessità di ridurre il tempo di avvio, diminuire il consumo di memoria e rendere lo sviluppo più comodo e piacevole. Negli ultimi anni, Java ha introdotto diversi miglioramenti, come funzionalità ergonomiche ottimizzate per i container e altro. Tuttavia, ottenere un funzionamento normale di Java in un container è ancora complicato. Pertanto, inizieremo esaminando alcune delle complessità interne di Java, che si manifestano in modo particolarmente acuto durante lo sviluppo di applicazioni Java orientate ai container.
Per cominciare, diamo un'occhiata alla storia.

Thread e container
A partire dalla versione 8u131, Java ha iniziato a supportare più o meno i container grazie a miglioramenti nelle funzionalità ergonomiche. In particolare, ora la JVM sa su quanti core di elaborazione sta girando e può configurare correttamente i pool di thread – di solito, pool fork/join. Certamente, è ottimo, ma supponiamo di avere un'applicazione web tradizionale che utilizza servlet HTTP e che gira su Tomcat, Jetty e simili. In tal caso, questa applicazione fornisce a ogni richiesta un thread separato e consente di bloccare quel thread in attesa di operazioni di input/output, ad esempio quando si accede a un database, a file o ad altri servizi. Questo significa che la dimensione di tale applicazione non dipende dal numero di core disponibili, ma dal numero di richieste simultanee. Inoltre, ciò implica che le quote o i limiti in Kubernetes per il numero di core non aiutano molto, e la situazione alla fine si risolverà con il throttling.
Esaurimento della memoria
I flussi sono memoria. Le limitazioni interne ai contenitori non sono affatto una panacea. Iniziate semplicemente ad aumentare il numero di applicazioni e flussi, e prima o poi vi troverete a fronteggiare una crescita critica della frequenza di switching e, di conseguenza, una degradazione delle prestazioni. Inoltre, se l'applicazione utilizza framework microservizi tradizionali o si connette a un database, o utilizza la memorizzazione nella cache, o in qualche altro modo consuma memoria, è chiaro che avete bisogno di uno strumento che consenta di guardare dentro la JVM e vedere come gestisce la memoria, senza uccidere la JVM stessa (ad esempio, XX:+UseCGroupMemoryLimitForHeap). E anche se a partire da Java 9 la JVM ha imparato a capire i cgroups e ad adattarsi di conseguenza, la riservazione e la gestione della memoria rimangono un compito piuttosto complesso.
Quote e limiti
Con Java 11 è stata introdotta la supporto per le quote di CPU (come PreferContainerQuotaForCPUCount). Kubernetes offre anche supporto per limiti e quote. Sì, tutto questo ha senso, ma se l'applicazione supera di nuovo la quota assegnata, torniamo al punto in cui la dimensione - come nel caso delle applicazioni Java tradizionali - è definita dal numero di core e dall'assegnazione di un thread separato per ogni richiesta, quindi ne deriva poco.
Inoltre, se si utilizzano quote e limiti o le funzionalità di scalabilità orizzontale (scale-out) della piattaforma alla base di Kubernetes, il problema non si risolve da solo. Stiamo semplicemente spendendo più risorse per risolvere il problema originale o finiamo per sprecare risorse. E se si tratta di un sistema ad alta disponibilità nel cloud pubblico, è quasi certo che cominciamo a utilizzare più risorse di quelle realmente necessarie.
E cosa fare con tutto questo?
In parole semplici, si devono utilizzare librerie e framework di I/O asincroni e non bloccanti come Netty, o Akka. Sono decisamente più adatti per lavorare in contenitori grazie alla loro natura reattiva. Grazie all'input/output non bloccante, lo stesso thread può gestire simultaneamente più richieste. Mentre una richiesta aspetta i risultati dell'input/output, il thread che la gestisce viene liberato e si occupa di un'altra richiesta. Quando i risultati dell'input/output arrivano infine, la elaborazione della prima richiesta continua. Alternando la gestione delle richieste all'interno dello stesso thread, è possibile ridurre il numero totale di thread e diminuire il consumo di risorse nella gestione delle richieste.
Con l'input/output non bloccante, il numero di core diventa un parametro chiave, poiché determina il numero di thread di input/output che possono essere eseguiti in parallelo. Se usato correttamente, consente di distribuire efficacemente il carico tra i core e gestire carichi più elevati con risorse inferiori.
Come, e questo è tutto?
No, c'è ancora qualcos'altro. La programmazione reattiva aiuta a sfruttare meglio le risorse, ma ha anche un costo. In particolare, sarà necessario riscrivere il codice secondo i principi della non bloccabilità ed evitare di bloccare i thread di input/output. E questo è un modello di sviluppo e di esecuzione completamente diverso. Anche se ci sono molte librerie utili, si tratta comunque di un cambiamento radicale nel modo di pensare.
Prima di tutto, è necessario imparare a scrivere codice che si esegue in modo asincrono. Una volta iniziato a utilizzare l'input/output non bloccante, è necessario specificare esplicitamente cosa deve accadere quando si riceve una risposta alla richiesta. Non è più possibile semplicemente bloccare e aspettare. In cambio, è possibile passare callback, utilizzare la programmazione reattiva o continuazioni. E non è tutto: per utilizzare l'input/output non bloccante, servono anche server e client non bloccanti, e idealmente ovunque. Nel caso dell'HTTP è semplice, ma ci sono anche database, sistemi di file e molto altro.
E sebbene la reattività totale offra la massima efficienza, un tale cambiamento può essere difficile da digerire nella pratica. Pertanto, la possibilità di combinare codice reattivo e imperativo diventa una condizione necessaria per:
- Utilizzare in modo efficace le risorse nelle aree più cariche del sistema software;
- Utilizzare un codice più semplice nello stile nelle altre parti.
Presentiamo Quarkus
In effetti, questo è il punto di Quarkus: unire i modelli reattivi e imperativi all'interno di un unico ambiente di esecuzione.
Alla base di Quarkus ci sono Vert.x e Netty, sopra i quali viene utilizzata una serie di framework e estensioni reattive, progettate per aiutare lo sviluppatore. Quarkus è destinato alla creazione non solo di microservizi HTTP, ma anche di architetture basate su eventi. Grazie alla sua natura reattiva, lavora molto efficacemente con i sistemi di messaggistica (Apache Kafka, AMQP, ecc.).
La vera astuzia sta nel come utilizzare lo stesso motore reattivo sia per il codice imperativo che per quello reattivo.

Quarkus riesce a farlo splendidamente. La scelta tra imperativo e reattivo è chiara: utilizzare il nucleo reattivo per entrambi. E ciò che aiuta molto è il codice non bloccante e veloce, che elabora quasi tutto ciò che passa attraverso il thread del ciclo degli eventi (thread dell'event-loop, noto anche come thread IO). Ma se hai applicazioni REST classiche o applicazioni lato client, Quarkus ha a disposizione un modello di programmazione imperativa. Ad esempio, il supporto HTTP in Quarkus si basa sull'utilizzo di un motore non bloccante e reattivo (Eclipse Vert.x e Netty). Tutte le richieste HTTP ricevute dall'applicazione passano inizialmente attraverso il ciclo degli eventi (IO Thread) e poi vengono inviate alla parte di codice che gestisce le richieste. A seconda della destinazione, il codice di gestione delle richieste può essere eseguito in un thread separato (il cosiddetto worker thread, utilizzato nel caso di servlet e Jax-RS) o può utilizzare il thread di input-output originale (rotta reattiva).

Per i connettori dei sistemi di messaggistica vengono utilizzati client non bloccanti che lavorano sopra il motore Vert.x. Pertanto, puoi inviare, ricevere e elaborare messaggi dai sistemi di messaggistica in modo efficace.
Sul sito è raccolto un certo numero di ottimi tutorial che aiutano a iniziare a lavorare con Quarkus:
Inoltre, abbiamo preparato lezioni pratiche online per familiarizzare con i vari aspetti della programmazione reattiva, e per seguirle è sufficiente un browser, non è necessaria alcuna IDE, e neanche un computer è obbligatorio. È possibile trovare queste lezioni .
Risorse utili
- Sito del progetto Quarkus –
- Progetto Quarkus su GitHub –
- Twitter del progetto Quarkus –
- Chat del progetto Quarkus –
- Forum del progetto Quarkus – !forum/quarkus-dev
10 video-lezioni su Quarkus per comprendere l'argomento
Come riportato sul sito , – è -stack Java orientato, progettato per GraalVM e OpenJDK HotSpot, composto dalle migliori librerie e standard Java.
Per aiutarvi a comprendere l'argomento, abbiamo selezionato 10 video-lezioni che trattano vari aspetti di Quarkus e esempi del suo utilizzo:
1. Introduzione a Quarkus: 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 i modelli di programmazione reattiva e imperativa in un'unica runtime, consentendo agli sviluppatori di variare flessibilmente le approcci nel lavoro con un ampio spettro di architetture distribuite di applicazioni. Scopri di più dalla lezione introduttiva qui sotto.

2. Quarkus: Java subatomica super veloce
Autore: Burr Sutter
La video-lezione dal seminario online DevNation Live dimostra come utilizzare Quarkus per ottimizzare applicazioni Java aziendali, API, microservizi e funzioni serverless in ambienti Kubernetes/OpenShift, rendendoli molto più leggeri, veloci e scalabili.

3. Quarkus e GraalVM: acceleriamo Hibernate a velocità super e lo riduciamo a dimensioni subatomiche
Autore: Sanne Grinovero
Dalla presentazione, imparerai come è nato Quarkus, come funziona e come rende le complesse librerie, come Hibernate ORM, compatibili con le immagini nativi di GraalVM.

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

5. Quarkus: scrivete con piacere
Autore: Edson Yanaga
Guida video per la creazione del tuo primo progetto Quarkus, che spiega perché Quarkus sta conquistando i cuori dei programmatori.

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

7. Quarkus: Java subatomica super veloce
Autore: Dimitris Andreadis
Panoramica sui vantaggi di Quarkus, riconosciuti dai programmatori: semplicità, velocità superiori, le migliori librerie e standard.

8. Quarkus e sistemi reattivi subatomici
Autore: Clement Escoffier
Grazie all'integrazione con GraalVM, Quarkus fornisce un'esperienza di sviluppo super veloce e un ambiente di esecuzione subatomico. L'autore parla del lato reattivo di Quarkus e di come utilizzarlo nella creazione di applicazioni reattive e di applicazioni con flussi di dati.

9. Quarkus e sviluppo rapido di applicazioni in Eclipse MicroProfile
Autore: John Clingan
Combinando Eclipse MicroProfile e Quarkus, i programmatori possono creare applicazioni container full-featured di MicroProfile che si avviano in pochi millisecondi. Nel video, viene spiegato in dettaglio come codificare un'app container di MicroProfile per il deployment sulla piattaforma Kubernetes.

10. Java, versione "Turbo"
Autore: Marcus Biel
L'autore mostra come utilizzare Quarkus per creare container Java ultra piccoli e super rapidi, che rappresentano una vera innovazione, specialmente negli ambienti serverless.

Fonte: habr.com
