Come Quarkus unisce programmazione imperativa e reattiva

Quest'anno prevediamo di sviluppare seriamente i temi dei container, Java Cloud-Native e Kubernetes. Un seguito logico a questi temi sarà la discussione sul framework Quarkus, già esaminato 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.

Come Quarkus unisce programmazione imperativa e reattiva

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 Quarkus 1.0, una release che segna una tappa importante nello sviluppo del progetto e offre molte funzionalità e possibilità interessanti (puoi leggerne di più in comunicato).

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 Java-gli sviluppatori possono sfruttare questi vantaggi.

Microservizi, architetture basate su eventi e serverless-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.

Come Quarkus unisce programmazione imperativa e reattiva

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, Vert.x 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:

  1. Utilizzare in modo efficace le risorse nelle aree più cariche del sistema software;
  2. 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.

Come Quarkus unisce programmazione imperativa e reattiva

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).

Come Quarkus unisce programmazione imperativa e 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 Quarkus.io è 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 qui.

Risorse utili

10 video-lezioni su Quarkus per comprendere l'argomento

Come riportato sul sito Quarkus.io, Quarkus – è Kubernetes-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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video

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.

Guarda il video


Fonte: habr.com
Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster