Cum Quarkus combină programarea imperativă și reactivă

Anul acesta ne propunem să dezvoltăm serios temele containerelor, Java Cloud-Native și Kubernetes. O continuare logică a acestor teme va fi discutarea framework-ului Quarkus, deja examinat pe Habr. Articolul de astăzi nu este atât despre cum funcționează «Java subatomică super rapidă», cât despre perspectivele pe care Quarkus le aduce în Enterprise.

Cum Quarkus combină programarea imperativă și reactivă

Java și JVM sunt încă extrem de populare, dar în contextul tehnologiilor fără server și al microserviciilor cloud-native, Java și alte limbaje pentru JVM sunt din ce în ce mai rar utilizate, deoarece consumă prea multă memorie și se încarcă prea lent, ceea ce le face inadecvate pentru utilizarea în containere cu o viață scurtă. Din fericire, această situație începe să se schimbe datorită lui Quarkus.

Java subatomică super rapidă a ajuns la un nou nivel!

42 de versiuni, 8 luni de muncă a comunității și 177 de dezvoltatori uimitori - toate acestea au dus la lansarea în noiembrie 2019 Quarkus 1.0, o versiune care marchează un punct de cotitură important în dezvoltarea acestui proiect și oferă o mulțime de caracteristici și funcționalități grozave (mai multe detalii pot fi citite în anunț).

Astăzi vom explica cum Quarkus combină modelele de programare imperativă și reactivă bazate pe un nucleu reactiv unic. Vom începe cu o scurtă excursie în istorie și apoi vom analiza în detaliu în ce constă dualitatea nucleului reactiv al Quarkus și cum Java-dezvoltatorii pot profita de aceste avantaje.

Microservicii, arhitecturi gestionate prin evenimente și funcții serverless – toate acestea sunt astăzi, ce se cheamă, în ascensiune. Recent, a devenit mult mai simplu și accesibil să construiești arhitecturi cloud-native, dar problemele persistă – în special pentru dezvoltatorii Java. De exemplu, în cazul funcțiilor serverless și microserviciilor există o necesitate acută de a reduce timpul de pornire, de a diminua consumul de memorie și de a face dezvoltarea lor o activitate mai comodă și plăcută. Java a adus câteva îmbunătățiri în ultimii ani, cum ar fi ergnomicile îmbunătățite pentru containere și altele. Totuși, obținerea unei funcționări normale a Java într-un container rămâne complexă. De aceea, vom începe cu analiza unor dificultăți interne ale Java, care se manifestă în mod distinct în dezvoltarea aplicațiilor Java orientate pe containere.-Funcțiile sunt, așadar, în prezent, în plină expansiune. De ceva vreme, crearea arhitecturilor orientate pe cloud a devenit mult mai ușoară și accesibilă, însă problemele persistă – în special pentru dezvoltatorii Java. De exemplu, în cazul funcțiilor serverless și al microserviciilor, există o necesitate acută de a reduce timpul de inițiere, de a diminua consumul de memorie și, totodată, de a face dezvoltarea lor mai convenabilă și plăcută. Java a adus în ultimii ani câteva îmbunătățiri, cum ar fi funcționalitatea ergonomics, adaptată pentru containere, și altele. Cu toate acestea, realizarea unei funcționări optime a Java într-un container este, în continuare, dificilă. Prin urmare, vom începe prin a analiza unele dintre complexitățile interne ale Java, care se manifestă în mod special în timpul dezvoltării aplicațiilor Java orientate pe containere.

Pentru început, haideți să ne întoarcem la istorie.

Cum Quarkus combină programarea imperativă și reactivă

Fluxuri și containere

Începând cu versiunea 8u131, Java a început să sprijine mai bine containerele prin îmbunătățiri ale funcționalității ergonomice. În special, acum JVM știe pe câte nuclee de procesor rulează și poate să-și ajusteze în mod corespunzător grupurile de fire – de obicei, grupuri fork/join. Fără îndoială, acest lucru este minunat, dar să presupunem că avem o aplicație web tradițională care folosește servlet-uri HTTP și este rulată în Tomcat, Jetty etc. Ca rezultat, această aplicație va aloca un fir separatat fiecărui request și îi va permite să blocheze acest fir în așteptarea operațiunilor de intrare-ieșire, de exemplu, atunci când se face apel la o bază de date, fișiere sau alte servicii. Asta înseamnă că dimensiunea unei astfel de aplicații depinde nu de numărul de nuclee disponibile, ci de numărul de cereri simultane. În plus, aceasta înseamnă că cotele sau limitele în Kubernetes privind numărul de nuclee nu vor ajuta prea mult, iar situația se va finaliza cu throttling.

Epuizarea memoriei

Firele sunt memorie. Iar restricțiile de memorie dintre containere nu sunt de niciun ajutor. Pur și simplu începeți să creșteți numărul de aplicații și fire, și mai devreme sau mai târziu veți întâlni o creștere critică a frecvenței comutărilor și, ca urmare, o degradare a performanței. În plus, dacă aplicația folosește framework-uri tradiționale de microservicii sau se conectează la o bază de date, sau utilizează caching, sau în orice alt mod consumă suplimentar memorie, este evident că aveți nevoie de un instrument care să vă permită să priviți în interiorul JVM-ului și să observați cum gestionează memoria, fără a afecta însăși JVM-ul (de exemplu, XX:+UseCGroupMemoryLimitForHeap). Chiar dacă începând cu Java 9, JVM-ul a învățat să recunoască cgroups și să se adapteze în mod corespunzător, rezervarea și gestionarea memoriei rămân niște sarcini destul de complexe.

Cote și limite

În Java 11 a apărut suport pentru cotele CPU (de genul PreferContainerQuotaForCPUCount). Kubernetes oferă, de asemenea, suport pentru limite și cote. Da, toate acestea au sens, dar, dacă aplicația depășește din nou cota alocată, revenim la situația în care dimensiunea – la fel ca în cazul aplicațiilor tradiționale Java – este determinată de numărul de nuclee și se alocă un fir separat pentru fiecare cerere, ceea ce înseamnă că toate acestea nu sunt de mare folos.
În plus, chiar dacă folosim cote și limite sau funcții de scalare orizontală (scale-out) ale platformei care stă la baza Kubernetes, problema nu se rezolvă de la sine. Pur și simplu cheltuim mai multe resurse pentru a rezolva problema inițială sau, în final, ajungem la un consum excesiv de resurse. Iar dacă este un sistem de înaltă încărcare într-un nor public, aproape cu siguranță începem să folosim mai multe resurse decât ar fi necesar.

Și ce să facem cu toate acestea?

Dacă vrem să o spunem simplu, ar trebui să folosim biblioteci și cadre de lucru asyncrone și non-blocante, precum Netty, Vert.x sau Akka. Acestea sunt mult mai potrivite pentru utilizarea în containere datorită naturii lor reactive. Datorită I/O-ului non-blocant, aceeași fire de execuție poate gestiona mai multe cereri simultan. În timp ce o cerere așteaptă rezultatele I/O-ului, firul care o procesează este eliberat și preia o altă cerere. Iar când rezultatele I/O-ului sosesc în sfârșit, procesarea primei cereri continuă. Alternând procesarea cererilor în cadrul aceluiași fir, putem reduce numărul total de fire și să scădem consumul de resurse pentru procesarea cererilor.

În cazul I/O-ului non-blocant, numărul de nuclee devine un parametru cheie, deoarece acesta determină numărul de fire de execuție I/O care pot fi executate în paralel. Folosit corect, acest lucru permite distribuirea eficientă a încărcăturii între nuclee și gestionarea sarcinilor mai mari cu mai puține resurse.

Cum, atât și asta?

Nu, mai este ceva. Programarea reactivă ajută la utilizarea mai bună a resurselor, dar are și un cost asociat. În special, codul va trebui rescris conform principiilor non-blocării și trebuie să evităm blocarea firelor de execuție I/O. Aceasta este o modelare complet diferită de dezvoltare și execuție. Și deși există o mulțime de biblioteci utile, tot rămâne o schimbare radicală în modul de gândire obișnuit.

În primul rând, trebuie să înveți să scrii cod care se execută în mod asincron. Odată ce începi să folosești intrarea-ieșirea neblocat, trebuie să specifici clar ce ar trebui să se întâmple când primești un răspuns la cerere. Pur și simplu să blochezi și să aștepți nu mai este o opțiune. În schimb, poți transmite apeluri inverse, folosi programarea reactivă sau continuarea. Dar asta nu este tot: pentru a utiliza intrarea-ieșirea neblocat, ai nevoie de servere și clienți neblocați, ideal în toate locurile. În cazul HTTP, totul este simplu, dar mai există și baze de date, sisteme de fișiere și multe altele.

Și deși reacția totală în serie oferă maxima eficiență, o astfel de schimbare poate fi greu de digerat în practică. Prin urmare, capacitatea de a combina codul reactiv și cel imperativ devine o condiție necesară pentru a:

  1. Utiliza eficient resursele în cele mai aglomerate direcții ale sistemului software;
  2. Folosi un cod mai simplu din punct de vedere stilistic în celelalte părți ale acestuia.

Îți prezentăm Quarkus

De fapt, acesta este scopul lui Quarkus – de a combina modelele reactive și imperative într-un singur mediu de execuție.

La baza Quarkus se află Vert.x și Netty, deasupra cărora se folosește o serie de cadre și extensii reactive, concepute pentru a ajuta dezvoltatorul. Quarkus este destinat să construiască nu doar microservicii HTTP, ci și arhitecturi bazate pe evenimente. Datorită naturii sale reactive, funcționează foarte eficient cu sistemele de mesagerie (Apache Kafka, AMQP etc.).

Toată miza stă în modul de utilizare a aceluiași motor reactiv atât pentru codul imperativ, cât și pentru cel reactiv.

Cum Quarkus combină programarea imperativă și reactivă

Quarkus se descurcă excelent cu asta. Alegerea între programarea imperativă și reactivă este evidentă – folosiți nucleul reactiv atât pentru una, cât și pentru cealaltă. Și ceea ce ajută mult este codul rapid non-blocant care procesează aproape tot ce trece prin firul ciclului de evenimente (event-loop thread, de asemenea – fir IO). Dar dacă aveți aplicații REST clasice sau aplicații pe partea clientului, Quarkus are modelul de programare imperativ pregătit. De exemplu, suportul HTTP în Quarkus este construit pe utilizarea unui motor non-blocant și reactiv (Eclipse Vert.x și Netty). Toate cererile HTTP primite de aplicația dumneavoastră trec mai întâi prin ciclul evenimentelor (IO Thread), apoi sunt trimise părții de cod care se ocupă de cereri. În funcție de destinație, codul de gestionare a cererilor poate fi apelat în cadrul unui fir separată (așa-numitul worker thread, folosit în cazul servletelor și Jax-RS) sau poate utiliza firul de intrare-ișire original (ruta reactivă).

Cum Quarkus combină programarea imperativă și reactivă

Pentru conectorii sistemelor de transmitere a mesajelor sunt utilizați clienți non-blocanți, care funcționează pe baza motorului Vert.x. Astfel, puteți trimite, primi și procesa eficient mesaje din sisteme de tip messaging middleware.

se menționează: Quarkus.io sunt disponibile mai multe ghiduri utile pentru a începe lucrul cu Quarkus:

În plus, am pregătit lecții practice online pentru a vă familiariza cu diverse aspecte ale programării reactive, iar pentru a le parcurge este suficient un browser; nu este necesară nicio IDE, iar un computer nu este obligatoriu. Puteți găsi aceste lecții aici.

Resurse utile

10 lecții video despre Quarkus pentru a vă familiariza cu subiectul

Așa cum se menționează pe site Quarkus.io, Quarkus , which combines Kubernetes-stiva Java orientată, optimizată pentru GraalVM și OpenJDK HotSpot și construită din cele mai bune biblioteci Java și standarde.

Pentru a vă ajuta să înțelegeți subiectul, am selectat 10 lecții video care abordează diverse aspecte ale Quarkus și exemple de utilizare:

1. Introducere în Quarkus: un framework Java de nouă generație pentru Kubernetes

Autori: Thomas Qvarnstrom și Jason Greene
Scopul proiectului Quarkus este de a crea o platformă Java pentru Kubernetes și medii serverless, precum și de a combina modelele reactive și imperative de programare într-un mediu de execuție unificat, astfel încât dezvoltatorii să poată varia flexibil abordarea în lucrul cu o gamă largă de arhitecturi distribuite ale aplicațiilor. Aflați mai multe din lecția introductivă de mai jos.

Redați video

2. Quarkus: Java subatomică superrapidă

Autor: Burr Sutter
Tutorialul video din cadrul DevNation Live demonstrează cum să utilizați Quarkus pentru a optimiza aplicațiile Java de corporație, API-urile, microserviciile și funcțiile serverless în medii Kubernetes/OpenShift, făcându-le mult mai mici, mai rapide și mai scalabile.

Redați video

3. Quarkus și GraalVM: accelerăm Hibernate la viteze super rapide și comprimăm la dimensiuni subatomice

Autor: Sanne Grinovero
Din prezentare veți afla cum a apărut Quarkus, cum funcționează acesta și cum permite interoperabilitatea bibliotecilor complexe, precum Hibernate ORM, cu imaginile native GraalVM.

Redați video

4. Învățăm să dezvoltăm aplicații serverless

Autor: Marthen Luther
În videoclipul de mai jos, este prezentat cum să creați o aplicație Java simplă folosind Quarkus și să o desfășurați ca aplicație serverless pe Knative.

Redați video

5. Quarkus: codificați cu plăcere

Autor: Edson Yanaga
Ghid video pentru crearea primului vostru proiect Quarkus, care ajută să înțelegeți de ce Quarkus câștigă inimile dezvoltatorilor.

Redați video

6. Java și containere – cum va fi viitorul lor comun

Autor: Mark Little
Această prezentare vă introduce în istoria Java și explică de ce Quarkus este viitorul Java.

Redați video

7. Quarkus: Java subatomică superrapidă

Autor: Dimitris Andreadis
O prezentare generală a avantajelor Quarkus, recunoscute de dezvoltatori: simplitate, viteze extreme, cele mai bune biblioteci și standarde.

Redați video

8. Quarkus și sistemele reactive subatomice

Autor: Clement Escoffier
Datorită integrării cu GraalVM, Quarkus oferă o experiență de dezvoltare super rapidă și un mediu de execuție subatomic. Autorul vorbește despre latura reactivă a Quarkus și cum să o folosim la crearea aplicațiilor reactive și aplicațiilor cu transmitere de date în flux.

Redați video

9. Quarkus și dezvoltarea rapidă a aplicațiilor în Eclipse MicroProfile

Autor: John Clingan
Prin combinarea Eclipse MicroProfile și Quarkus, dezvoltatorii pot crea aplicații containerizate MicroProfile complet funcționale, care pornesc în câteva zeci de milisecunde. În acest videoclip se analizează în detaliu cum se poate codifica o aplicație containerizată MicroProfile pentru desfășurarea pe platforma Kubernetes.

Redați video

10. Java, versiunea „Turbo”

Autor: Marcus Biel
Autorul arată cum se poate utiliza Quarkus pentru a crea containere Java super-mici și super-rapide, permițând astfel o adevărată revoluție, în special în medii fără server.

Redați video


Sursa: habr.com
Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster