Wie Quarkus imperative und reaktive Programmierung kombiniert

In diesem Jahr planen wir die ernsthafte Entwicklung von Containerthemen, Cloud-Native Java und Kubernetes . Eine logische Fortsetzung dieser Themen wird die Geschichte über den Quarkus Rahmen sein, bereits als auf Habré. Der heutige Artikel konzentriert sich weniger auf das „subatomare ultraschnelle Java-Gerät“ als vielmehr auf die Perspektiven, die Quarkus für Enterprise bietet. (Registrieren Sie sich übrigens und besuchen Sie unser Webinar „ Dies ist das native Java-Framework von Quarkus - Kubernetes “, das am 27. Mai stattfinden wird. Wir werden zeigen, wie Sie bei Null anfangen oder vorgefertigte Lösungen übertragen können.)



Java und die JVM sind immer noch sehr beliebt, aber wenn mit serverlosen Technologien und Cloud-orientierten Mikrodiensten gearbeitet wird, werden Java und andere Sprachen für die JVM immer weniger verwendet, da sie zu viel Speicherplatz beanspruchen und zu langsam geladen werden, was sie ungeeignet macht Verwendung mit kurzlebigen Behältern. Glücklicherweise beginnt sich diese Situation dank Quarkus derzeit zu ändern.

Ultraschnelles subatomares Java hat ein neues Level erreicht!


42 Releases, 8 Monate Community-Arbeit und 177 großartige Entwickler - das Ergebnis war die Veröffentlichung von Quarkus 1.0 im November 2019 , einem Release, das einen wichtigen Meilenstein in der Entwicklung des Projekts darstellt und viele coole Funktionen und Fähigkeiten bietet (mehr dazu in der Ankündigung ). .

Heute werden wir erzählen, wie Quarkus imperative und reaktive Programmiermodelle basierend auf einem einzigen reaktiven Kern kombiniert. Wir beginnen mit einer kurzen Geschichte und schauen uns dann genauer an, wie der duale Kern von Quarkus reagiert und wie Java- Entwickler diese nutzen können.

Mikroservisy , ereignisgesteuerte Architektur und serverlos-Funktionen - all dies ist heute, wie sie sagen, auf dem Vormarsch. In letzter Zeit ist die Erstellung von Cloud-basierten Architekturen viel einfacher und kostengünstiger geworden, aber es bestehen weiterhin Probleme - insbesondere für Java-Entwickler. Beispielsweise besteht bei serverlosen Funktionen und Microservices eine dringende Notwendigkeit, die Startzeit zu verkürzen, den Speicherverbrauch zu reduzieren und deren Entwicklung bequemer und angenehmer zu gestalten. Java hat in den letzten Jahren verschiedene Verbesserungen vorgenommen, z. B. die für Container modifizierte Ergonomiefunktionalität usw. Es ist jedoch immer noch nicht einfach, Java im Container zum Laufen zu bringen. Daher werden wir uns zunächst mit einigen der komplexen Komplexitäten von Java befassen, die besonders bei der Entwicklung von containerorientierten Java-Anwendungen akut sind.

Wenden wir uns zunächst der Geschichte zu.


Streams und Container


Ab Version 8u131 verfügt Java aufgrund verbesserter Ergonomiefunktionen über mehr oder weniger unterstützte Container. Insbesondere weiß die JVM jetzt, auf wie vielen Prozessorkernen sie ausgeführt wird, und kann Thread-Pools ordnungsgemäß konfigurieren - normalerweise Fork / Join-Pools. Das ist natürlich großartig, aber nehmen wir an, wir haben eine traditionelle Webanwendung, die HTTP-Servlets verwendet und auf Tomcat, Jetty usw. ausgeführt wird. Infolgedessen gibt diese Anwendung jeder Anforderung einen separaten Stream und ermöglicht es ihr, diesen Stream zu blockieren, während sie auf E / A-Vorgänge wartet, z. B. beim Zugriff auf eine Datenbank, Dateien oder andere Dienste. Das heißt, die Größe einer solchen Anwendung hängt nicht von der Anzahl der verfügbaren Kerne ab, sondern von der Anzahl der gleichzeitigen Anforderungen. Darüber hinaus bedeutet dies, dass Quoten oder Grenzen in Kubernetes durch die Anzahl der Kerne hier nicht besonders hilfreich sind.und der Deal wird im Trab enden.

Der Speicher geht zur Neige


Streams sind Speicher. Und Speicherbeschränkungen innerhalb eines Containers sind keineswegs ein Allheilmittel. Beginnen Sie einfach damit, die Anzahl der Anwendungen und Threads zu erhöhen, und früher oder später werden Sie eine kritische Erhöhung der Schaltfrequenz und infolgedessen eine Verschlechterung der Leistung feststellen. Wenn die Anwendung herkömmliche Microservice-Frameworks verwendet oder eine Verbindung zur Datenbank herstellt oder Caching verwendet oder irgendwie zusätzlich Speicher verbraucht, benötigen Sie unbedingt ein Tool, mit dem Sie in die JVM schauen und sehen können, wie sie den Speicher verwaltet und nicht beendet JVM selbst (z. B. XX: + UseCGroupMemoryLimitForHeap). Und trotz der Tatsache, dass die JVM ab Java 9 gelernt hat, cgroups zu akzeptieren und sich entsprechend anzupassen, bleibt das Sichern und Verwalten des Speichers eine ziemlich komplizierte Angelegenheit.

Quoten und Grenzen


Java 11 führte die Unterstützung von CPU-Kontingenten ein (wie PreferContainerQuotaForCPUCount). Kubernetes bietet auch Limit- und Quotenunterstützung. Ja, all dies ist sinnvoll, aber wenn die Anwendung das zugewiesene Kontingent erneut überschreitet, kommen wir erneut zu dem Schluss, dass die Größe - wie bei herkömmlichen Java-Anwendungen - durch die Anzahl der Kerne und die Zuweisung eines separaten Threads für jede Anforderung bestimmt wird Das alles hat wenig Sinn.
Wenn Sie außerdem Quoten und Grenzen oder Funktionen der horizontalen (Scale-Out-) Skalierung der Plattform verwenden, die Kubernetes zugrunde liegt, löst sich das Problem auch nicht von selbst. Wir geben einfach mehr Ressourcen für die Lösung des ursprünglichen Problems aus oder verwenden daher Ressourcen. Und wenn es sich um ein hoch ausgelastetes System in einer öffentlichen, öffentlichen Cloud handelt, werden wir mit ziemlicher Sicherheit mehr Ressourcen verbrauchen, als es wirklich benötigt.

Und was tun mit all dem?


Verwenden Sie auf einfache Weise asynchrone und nicht blockierende E / A-Bibliotheken und Frameworks wie Netty, Vert.x oder Akka. Sie sind aufgrund ihrer reaktiven Natur viel besser für die Arbeit in Behältern geeignet. Dank nicht blockierender E / A kann derselbe Thread mehrere gleichzeitige Anforderungen gleichzeitig verarbeiten. Während eine Anforderung auf E / A-Ergebnisse wartet, wird ihr Verarbeitungsthread freigegeben und für eine andere Anforderung verwendet. Und wenn die E / A-Ergebnisse endlich eintreffen, wird die Verarbeitung der ersten Anforderung fortgesetzt. Durch abwechselnde Anforderungsverarbeitung innerhalb desselben Streams können Sie die Gesamtzahl der Threads und den Ressourcenverbrauch für die Verarbeitung von Anforderungen reduzieren.

Bei nicht blockierenden E / A wird die Anzahl der Kerne zu einem Schlüsselparameter, da sie die Anzahl der E / A-Threads bestimmt, die parallel ausgeführt werden können. Bei korrekter Verwendung können Sie so die Last effektiv auf die Kerne verteilen und höhere Lasten mit weniger Ressourcen bewältigen.

Wie und ist das alles?


Nein, da ist noch eine Sache. Reaktive Programmierung hilft, Ressourcen besser zu nutzen, hat aber auch ihren Preis. Insbesondere muss der Code gemäß den Prinzipien der Nichtblockierung neu geschrieben werden und eine Blockierung der Eingabe-Ausgabe-Streams vermeiden. Und dies ist ein völlig anderes Modell für Entwicklung und Implementierung. Und obwohl es viele nützliche Bibliotheken gibt, ist dies immer noch eine grundlegende Änderung der üblichen Denkweise.

Zunächst müssen Sie lernen, wie Sie asynchron ausgeführten Code schreiben. Sobald Sie nicht blockierende E / A verwenden, müssen Sie explizit vorschreiben, was passieren soll, wenn Sie eine Antwort auf die Anfrage erhalten. Nur blockieren und warten wird fehlschlagen. Im Gegenzug können Sie Rückrufe weiterleiten, reaktive Programmierung verwenden oder fortfahren. Aber das ist noch nicht alles: Um nicht blockierende E / A zu verwenden, benötigen Sie sowohl nicht blockierende Server als auch Clients, vorzugsweise überall. Bei HTTP ist alles einfach, aber es gibt auch eine Datenbank, Dateisysteme und vieles mehr.

Obwohl die vollständige End-to-End-Reaktivität maximale Effizienz ergibt, kann eine solche Verschiebung in der Praxis schwierig zu verdauen sein. Daher wird die Fähigkeit, reaktiven und imperativen Code zu kombinieren, zu einer notwendigen Bedingung, um:

  1. Verwenden Sie Ressourcen effektiv in den am stärksten belasteten Bereichen des Softwaresystems.
  2. Verwenden Sie in den anderen Teilen einen einfacheren Stilcode.

Wir stellen Quarkus vor


Tatsächlich ist dies die Essenz von Quarkus - reaktive und imperative Modelle in einer Laufzeitumgebung zu kombinieren.

Quarkus basiert auf Vert.x und Netty, auf denen eine Reihe reaktiver Frameworks und Erweiterungen verwendet werden, um dem Entwickler zu helfen. Quarkus wurde entwickelt, um nicht nur HTTP-Microservices, sondern auch ereignisgesteuerte Architekturen zu erstellen. Aufgrund seiner reaktiven Natur arbeitet es sehr effizient mit Messagingsystemen (Apache Kafka, AMQP usw.).

Der Trick besteht darin, dasselbe Strahltriebwerk sowohl für imperativen als auch für reaktiven Code zu verwenden.



Quarkus macht das hervorragend. Die Wahl zwischen Imperativ und Reaktiv liegt auf der Hand - sowohl der eine als auch der andere reaktive Kern zu verwenden. Und mit dem, was es sehr hilft, ist es mit schnellem, nicht blockierendem Code, der fast alles verarbeitet, was durch den Ereignisschleifenthread (Ereignisschleifenthread, auch bekannt als E / A-Thread) geht. Wenn Sie jedoch klassische REST- oder clientseitige Anwendungen haben, ist Quarkus für ein zwingendes Programmiermodell bereit. Beispielsweise basiert die HTTP-Unterstützung in Quarkus auf der Verwendung eines nicht blockierenden Triebwerks (Eclipse Vert.x und Netty). Alle von Ihrer Anwendung empfangenen HTTP-Anforderungen durchlaufen zuerst die Ereignisschleife (IO-Thread) und werden dann an den Teil des Codes gesendet, der die Anforderungen verwaltet.Je nach Ziel kann der Anforderungssteuercode in einem separaten Thread (dem sogenannten Worker-Thread, der bei Servlets und Jax-RS verwendet wird) aufgerufen werden oder der ursprüngliche Eingabe-Ausgabe-Stream (reaktive Route, reaktive Route) verwendet werden.



Nicht blockierende Clients, die über der Vert.x-Engine arbeiten, werden für Konnektoren von Messagingsystemen verwendet. Daher können Sie Nachrichten von Messaging-Systemen der Middleware-Klasse effizient senden, empfangen und verarbeiten.

Auf der Website Quarkus.io wurden einige gute Richtlinien zusammengestellt, die Ihnen den Einstieg in Quarkus erleichtern sollen:


Darüber hinaus haben wir praktische Online-Lektionen vorbereitet, um Sie mit verschiedenen Aspekten der reaktiven Programmierung vertraut zu machen. Darüber hinaus reicht nur ein Browser aus, um sie zu vervollständigen. Hierfür ist keine IDE erforderlich und ein Computer ist nicht erforderlich. Diese Lektionen finden Sie hier .

Nützliche Ressourcen




10 Quarkus-Video-Tutorials, um sich mit dem Thema vertraut zu machen


Wie Quarkus.io auf der Website schreibt , ist Quarkus ein Kubernetes- orientierter Java-Stack, der von GraalVM und OpenJDK HotSpot geschärft und aus den besten Java-Bibliotheken und -Standards kompiliert wurde.

Um Ihnen das Verständnis des Themas zu erleichtern, haben wir 10 Video-Tutorials ausgewählt, die verschiedene Aspekte von Quarkus und Beispiele für dessen Verwendung abdecken:

1. Einführung in Quarkus: Das Java Framework der nächsten Generation für Kubernetes


Autoren: Thomas Qvarnstrom und Jason Greene
Ziel des Quarkus-Projekts ist es, eine Java-Plattform für Kubernetes und serverlose Umgebungen zu erstellen sowie reaktive und imperative Programmiermodelle in einer einzigen Laufzeit zu kombinieren, damit Entwickler kann den Ansatz flexibel variieren, wenn mit einer Vielzahl verteilter Anwendungsarchitekturen gearbeitet wird. Erfahren Sie mehr aus der Einführungsvorlesung unten.



2. Quarkus: ultraschnelles subatomares Java


Autor: Burr Sutter Ein
Video-Tutorial aus der Online-Vorlesung von DevNation Live zeigt, wie Sie mit Quarkus Java-Unternehmensanwendungen, APIs, Microservices und serverlose Funktionen in Kubernetes / OpenShift optimieren, um sie viel kleiner, schneller und skalierbarer zu machen.



3. Quarkus und GraalVM: Wir beschleunigen den Ruhezustand auf Supergeschwindigkeiten und drücken auf subatomare Größen


Autor: Sane Grinovero (Sanne Grinovero)
In der Präsentation erfahren Sie, wie Quarkus erschien, wie es funktioniert und wie Sie komplexe Bibliotheken wie Hibernate ORM mit nativen GraalVM-Bildern kompatibel machen können.



4. Lernen, serverlose Anwendungen zu entwickeln


Gepostet von Marthen Luther
Das folgende Video zeigt, wie Sie mit Quarkus eine einfache Java-Anwendung erstellen und als serverlose Anwendung auf Knative bereitstellen.



5. Quarkus: Code mit Vergnügen


Gepostet von Edson Yanaga
Wideguide, um Ihr erstes Quarkus-Projekt zu erstellen und zu verstehen, warum Quarkus die Herzen der Entwickler erobert.



6. Java und Container - was wird ihre gemeinsame Zukunft sein


Gepostet von Mark Little
Diese Präsentation stellt die Geschichte von Java vor und erklärt, warum Quarkus die Zukunft von Java ist.



7. Quarkus: ultraschnelles subatomares Java


Autor: Dimitris Andreadis Dimitris Andreadis
Ein Überblick über die renommierten Entwickler von Quarkus: Einfachheit, ultraschnelle Geschwindigkeiten, Top-Bibliotheken und Standards.



8. Quarkus und subatomare reaktive Systeme



Gepostet von Clement Escoffier Durch die Integration mit GraalVM bietet Quarkus ultraschnelle Entwicklungserfahrung und eine subatomare Laufzeit. Der Autor spricht über die reaktive Seite von Quarkus und wie man sie beim Erstellen reaktiver Anwendungen und Streaming-Anwendungen verwendet.



9. Quarkus und schnelle Anwendungsentwicklung bei Eclipse MicroProfile


Gepostet von John Clingan Durch die
Kombination von Eclipse MicroProfile und Quarkus können Entwickler voll funktionsfähige MicroProfile-Containeranwendungen erstellen, die in wenigen zehn Millisekunden ausgeführt werden. Das Video beschreibt, wie die MicroProfile-Containeranwendung für die Bereitstellung auf der Kubernetes-Plattform codiert wird.



10. Java, Turbo-Version


Gepostet von Marcus Biel
Der Autor zeigt, wie man mit Quarkus superkleine und superschnelle Java-Container für einen echten Durchbruch erstellt, insbesondere in Umgebungen ohne Server.


All Articles