Wie Quarkus imperatives und reaktives Programmieren vereint

In diesem Jahr planen wir, uns ernsthaft mit dem Thema Containerentwicklung zu beschäftigen, Cloud-Native Java und Kubernetes. Eine logische Fortsetzung dieser Themen wird die Vorstellung des Quarkus-Frameworks sein, das bereits auf Habré behandelt wurde. Der heutige Artikel widmet sich nicht nur der Architektur der „subatomaren ultraschnellen Java“, sondern auch den Perspektiven, die Quarkus für Unternehmen mit sich bringt.

Wie Quarkus imperatives und reaktives Programmieren vereint

Java und JVM sind nach wie vor äußerst beliebt, doch bei der Arbeit mit serverlosen Technologien und cloudbasierten Mikrodiensten kommen Java und andere JVM-Sprachen immer seltener zum Einsatz, da sie zu viel Speicherplatz benötigen und zu langsam laden, was sie für den Einsatz in kurzlebigen Containern unpraktisch macht. Glücklicherweise beginnt sich diese Situation dank Quarkus gerade zu ändern.

Die ultraschnelle subatomare Java hat ein neues Level erreicht!

42 Releases, 8 Monate Community-Arbeit und 177 beeindruckende Entwickler – dies führte zur Veröffentlichung von Quarkus 1.0, einem Release, das einen wichtigen Meilenstein in der Projektentwicklung darstellt und zahlreiche großartige Funktionen und Möglichkeiten bietet (mehr darüber können Sie im Ankündigung lesen)).

Heute zeigen wir, wie Quarkus Modelle der imperativen und reaktiven Programmierung auf der Grundlage eines einheitlichen reaktiven Kerns vereint. Wir beginnen mit einem kurzen historischen Rückblick und werden dann detailliert erörtern, was den Dualismus des reaktiven Kerns von Quarkus ausmacht und wie Java-Entwickler von diesen Vorteilen profitieren können.

Mikroservices, ereignisgesteuerten Architekturen und serverless-Funktionen – all dies ist heute, was man sozusagen im Trend liegt. Seit kurzem ist die Erstellung von cloud-orientierten Architekturen erheblich einfacher und zugänglicher geworden, dennoch bestehen Probleme – insbesondere für Java-Entwickler. Zum Beispiel besteht bei serverlosen Funktionen und Microservices ein dringender Bedarf, die Startzeit zu verkürzen, den Speicherverbrauch zu senken und die Entwicklung insgesamt angenehmer und benutzerfreundlicher zu gestalten. In den letzten Jahren hat Java einige Verbesserungen gebracht, wie optimierte Funktionen für Container und mehr. Doch eine ordnungsgemäße Ausführung von Java in einem Container bleibt nach wie vor eine Herausforderung. Daher beginnen wir mit einer Betrachtung einiger interner Herausforderungen von Java, die besonders stark bei der Entwicklung von containerbasierten Java-Anwendungen hervortreten.

Zunächst werfen wir einen Blick auf die Geschichte.

Wie Quarkus imperatives und reaktives Programmieren vereint

Threads und Container

Mit der Version 8u131 hat Java begonnen, Container besser zu unterstützen, dank Verbesserungen in der Ergonomie-Funktionalität. Insbesondere weiß die JVM jetzt, auf wie vielen Prozessorkernen sie läuft und kann entsprechend die Thread-Pools anpassen – typischerweise Fork/Join-Pools. Das ist zweifellos großartig, aber nehmen wir an, wir haben eine traditionelle Webanwendung, die HTTP-Servlets nutzt und auf Tomcat, Jetty und anderen Plattformen läuft. In diesem Fall wird die Anwendung für jede Anfrage einen eigenen Thread erzeugen und diesen Thread blockieren, während sie auf Eingabe-/Ausgabeoperationen wartet, beispielsweise beim Zugriff auf Datenbanken, Dateien oder andere Dienste. Das bedeutet, dass die Größe einer solchen Anwendung nicht von der Anzahl der verfügbaren Kerne abhängt, sondern von der Anzahl der gleichzeitigen Anfragen. Darüber hinaus bedeutet dies, dass Quoten oder Limits in Kubernetes bezüglich der Anzahl der Kerne hier nicht wirklich helfen werden, und letztendlich wird es zu Drosselungen führen.

Speichererschöpfung

Threads sind der Speicher. Und interne containerbezogene Speicherbeschränkungen sind keineswegs die Lösung für alle Probleme. Beginnen Sie einfach damit, die Anzahl der Anwendungen und Threads zu erhöhen, und irgendwann werden Sie unweigerlich mit einer kritischen Zunahme der Kontextwechselraten konfrontiert, was wiederum die Leistung beeinträchtigt. Darüber hinaus, wenn Ihre Anwendung traditionelle Microservices-Frameworks verwendet, mit Datenbanken verbunden ist, Caching nutzt oder auf andere Weise zusätzlichen Speicher verbraucht, benötigen Sie definitiv ein Werkzeug, das Ihnen einen Einblick in die JVM gewährt und zeigt, wie sie den Speicher verwaltet, ohne die JVM selbst zu gefährden (zum Beispiel XX:+UseCGroupMemoryLimitForHeap). Und selbst wenn die JVM seit Java 9 in der Lage ist, cgroups zu erkennen und sich entsprechend anzupassen, bleibt die Reservierung und Verwaltung von Speicher eine recht komplexe Angelegenheit.

Kontingente und Limits

In Java 11 gibt es Unterstützung für CPU-Quotas (zum Beispiel PreferContainerQuotaForCPUCount). Kubernetes bietet ebenfalls Unterstützung für Limits und Quotas. Das ist sinnvoll, aber wenn die Anwendung erneut die zugewiesene Quote übersteigt, gelangen wir wieder zu der Frage, wie bei traditionellen Java-Anwendungen, nämlich dass die Größe nach der Anzahl der Kerne bestimmt wird und jedem Request ein separater Thread zugewiesen wird. Das bringt unterm Strich nicht viel.
Darüber hinaus wird durch die Verwendung von Quotas und Limits oder den Funktionen der horizontalen Skalierung der zugrunde liegenden Kubernetes-Plattform das Problem nicht gelöst. Wir verschwenden einfach mehr Ressourcen, um das ursprüngliche Problem zu lösen, oder landen schließlich in einer Situation mit Ressourcenüberverbrauch. In einem hochbelasteten System in einer öffentlichen Cloud verwenden wir wahrscheinlich viel mehr Ressourcen, als tatsächlich nötig wären.

Was kann man mit all dem anfangen?

Einfach gesagt, sollte man asynchrone und nicht blockierende Ein- und Ausgabebibliotheken sowie Frameworks wie Netty verwenden, Vert.x oder Akka. Sie sind deutlich besser geeignet für Container-Anwendungen aufgrund ihrer reaktiven Natur. Dank der nicht-blockierenden Eingabe/Ausgabe kann derselbe Thread mehrere gleichzeitige Anfragen bearbeiten. Während eine Anfrage auf Eingabe/Ausgabe-Ergebnisse wartet, wird der sie verarbeitende Thread freigegeben und bearbeitet eine andere Anfrage. Sobald die Ergebnisse der Eingabe/Ausgabe eintreffen, wird die Bearbeitung der ersten Anfrage fortgesetzt. Durch die alternierende Bearbeitung von Anfragen innerhalb desselben Threads kann die Gesamtzahl der Threads verringert und der Ressourcenverbrauch für die Bearbeitung von Anfragen gesenkt werden.

Bei nicht-blockierender Eingabe/Ausgabe wird die Anzahl der Kerne zu einem entscheidenden Parameter, da sie bestimmt, wie viele Eingabe/Ausgabe-Threads parallel ausgeführt werden können. Bei richtiger Verwendung ermöglicht dies eine effiziente Lastverteilung zwischen den Kernen und die Bewältigung höherer Lasten mit weniger Ressourcen.

Wie, und das war's?

Nein, es gibt noch mehr. Reaktive Programmierung hilft, Ressourcen effizienter zu nutzen, hat aber auch ihren Preis. Insbesondere muss der Code entsprechend den Prinzipien der Nichtblockierung umgeschrieben werden, um eine Blockierung von Ein-/Ausgabeströmen zu vermeiden. Das erfordert ein ganz anderes Entwicklungs- und Ausführungsmodell. Und obwohl es viele nützliche Bibliotheken gibt, ist es dennoch ein radikaler Wandel in der gewohnten Denkweise.

Zunächst müssen Sie lernen, Code zu schreiben, der asynchron ausgeführt wird. Sobald Sie mit nicht blockierenden Ein-/Ausgaben arbeiten, müssen Sie ausdrücklich angeben, was passieren soll, wenn eine Antwort auf die Anfrage eintrifft. Einfach blockieren und warten funktioniert nicht mehr. Stattdessen können Sie Rückrufe übergeben, reaktive Programmierung verwenden oder Fortsetzungen nutzen. Aber das ist noch nicht alles: Um nicht blockierende Ein-/Ausgaben zu verwenden, benötigen Sie ebenfalls nicht blockierende Server und Clients, idealerweise überall. Bei HTTP ist das einfach, aber es gibt auch Datenbanken, Dateisysteme und vieles mehr.

Obwohl eine vollständige durchgängige Reaktivität maximale Effizienz bietet, kann ein solcher Wandel in der Praxis schwierig umzusetzen sein. Daher wird die Möglichkeit, reaktiven und imperativen Code zu kombinieren, zu einer wesentlichen Voraussetzung für:

  1. Die Ressourcen in den am stärksten belasteten Bereichen des Softwaresystems effektiv zu nutzen;
  2. In den anderen Teilen einen einfacheren Code-Stil zu verwenden.

Präsentation von Quarkus

Darum geht es bei Quarkus – die reaktiven und imperativen Modelle in einer einzigen Laufzeitumgebung zu vereinen.

Quarkus basiert auf Vert.x und Netty, über denen eine Reihe von reaktiven Frameworks und Erweiterungen genutzt wird, um den Entwicklern zu helfen. Quarkus ist nicht nur für die Erstellung von HTTP-Mikroservicen, sondern auch für ereignisgesteuerte Architekturen gedacht. Aufgrund seiner reaktiven Natur arbeitet es äußerst effizient mit Nachrichtenübertragungssystemen (Apache Kafka, AMQP usw.).

Der ganze Trick liegt darin, denselben reaktiven Motor sowohl für imperativen als auch für reaktiven Code zu verwenden.

Wie Quarkus imperatives und reaktives Programmieren vereint

Quarkus meistert das hervorragend. Die Wahl zwischen imperativem und reaktivem Programmierungsansatz ist klar – nutzen Sie für beides den reaktiven Kern. Dabei unterstützt es besonders gut beim schnellen, nicht blockierenden Code, der fast alles verarbeitet, was durch den Ereignisloop (event-loop thread oder auch IO thread) läuft. Wenn Sie jedoch klassische REST-Anwendungen oder clientseitige Anwendungen haben, hält Quarkus die imperative Programmiermodelle bereit. Beispielsweise basiert die HTTP-Unterstützung in Quarkus auf der Nutzung eines nicht blockierenden und reaktiven Engines (Eclipse Vert.x und Netty). Alle HTTP-Anfragen, die Ihre Anwendung erhält, durchlaufen zunächst den Ereignisloop (IO Thread) und werden dann an den Teil des Codes weitergeleitet, der die Anfragen verwaltet. Je nach Zielort kann der Anfrageverwaltungs-Code in einem separaten Thread (dem sogenannten Worker Thread, was bei Servlets und Jax-RS der Fall ist) aufgerufen werden oder den ursprünglichen Eingabe-/Ausgabethread (reaktiver Route) nutzen.

Wie Quarkus imperatives und reaktives Programmieren vereint

Für Nachrichtensysteme werden nicht blockierende Clients verwendet, die auf der Vert.x-Engine basieren. Dadurch können Sie Nachrichten von Messaging-Middleware-Systemen effizient senden, empfangen und verarbeiten.

Auf der Website Quarkus.io finden Sie eine Reihe nützlicher Anleitungen, die Ihnen den Einstieg in Quarkus erleichtern:

Darüber hinaus haben wir Online-Workshops vorbereitet, die verschiedene Aspekte der reaktiven Programmierung vorstellen. Sie benötigen lediglich einen Browser; eine IDE oder ein Computer sind nicht erforderlich. Diese Workshops finden Sie unter hier.

Nützliche Ressourcen

10 Videos zu Quarkus, um sich einzuarbeiten

Wie auf der Website geschrieben Quarkus.io, Quarkus – ist es Kubernetes-orientierter Java-Stack, der für GraalVM und OpenJDK HotSpot optimiert ist und aus den besten Java-Bibliotheken und -Standards besteht.

Um Ihnen bei dem Thema zu helfen, haben wir 10 Videotutorials ausgewählt, die verschiedene Aspekte von Quarkus und dessen Einsatzmöglichkeiten behandeln:

1. Einführung in Quarkus: Das moderne Java-Framework für Kubernetes

Autoren: Thomas Qvarnstrom und Jason Greene
Das Ziel des Quarkus-Projekts ist es, eine Java-Plattform für Kubernetes und serverless Umgebungen zu schaffen und die reaktive sowie die imperative Programmiermodelle innerhalb einer einheitlichen Laufzeitumgebung zu vereinen, damit Entwickler flexibel zwischen verschiedenen Ansätzen bei der Arbeit mit einer Vielzahl verteilter Anwendungsarchitekturen wechseln können. Erfahren Sie mehr in der einführenden Vorlesung unten.

Video abspielen

2. Quarkus: Überragende Geschwindigkeit für Java

Autor: Burr Sutter
Das Videotutorial aus der Online-Vorlesung DevNation Live zeigt, wie Sie Quarkus zur Optimierung von Unternehmens-Java-Anwendungen, APIs, Microservices und serverless Funktionen in Kubernetes/OpenShift nutzen können, wodurch diese erheblich kleiner, schneller und skalierbarer werden.

Video abspielen

3. Quarkus und GraalVM: Wir beschleunigen Hibernate auf Höchstgeschwindigkeiten und reduzieren es auf subatomare Größen

Autor: Sanne Grinovero
In der Präsentation erfahren Sie, wie Quarkus entstanden ist, wie es funktioniert und wie komplexe Bibliotheken wie Hibernate ORM mit GraalVM-Native-Images kompatibel gemacht werden können.

Video abspielen

4. Wir lernen, serverless Anwendungen zu entwickeln

Autor: Marthen Luther
Im folgenden Video sehen Sie, wie Sie mit Quarkus eine einfache Java-Anwendung erstellen und diese als serverless Anwendung auf Knative bereitstellen.

Video abspielen

5. Quarkus: Programmieren mit Freude

Autor: Edson Yanaga
Ein video-guide für Ihr erstes Quarkus-Projekt, der erklärt, warum Quarkus die Herzen der Entwickler erobert.

Video abspielen

6. Java und Container – wie sieht ihre gemeinsame Zukunft aus?

Autor: Mark Little
Diese Präsentation gibt einen Überblick über die Geschichte von Java und erklärt, warum Quarkus die Zukunft von Java ist.

Video abspielen

7. Quarkus: ultraschnelles subatomares Java

Autor: Dimitris Andreadis
Eine Übersicht über die von Entwicklern anerkannten Vorteile von Quarkus: Einfachheit, extreme Geschwindigkeiten, beste Bibliotheken und Standards.

Video abspielen

8. Quarkus und subatomare reaktive Systeme

Autor: Clement Escoffier
Dank der Integration mit GraalVM bietet Quarkus eine extrem schnelle Entwicklungsumgebung und eine subatomare Ausführungsumgebung. Der Autor spricht über die reaktive Seite von Quarkus und wie man sie beim Erstellen reaktiver Anwendungen und Streaming-Anwendungen nutzen kann.

Video abspielen

9. Quarkus und die schnelle Anwendungsentwicklung in Eclipse MicroProfile

Autor: John Clingan
Durch die Kombination von Eclipse MicroProfile und Quarkus können Entwickler voll funktionsfähige Containeranwendungen von MicroProfile erstellen, die in nur wenigen Millisekunden gestartet werden. Im Video wird ausführlich erläutert, wie man eine Containeranwendung von MicroProfile für die Bereitstellung auf der Kubernetes-Plattform erstellt.

Video abspielen

10. Java, Version 'Turbo'

Autor: Marcus Biel
Der Autor zeigt, wie man Quarkus verwendet, um extrem kleine und extrem schnelle Java-Container zu erstellen, die einen echten Durchbruch ermöglichen, insbesondere in serverlosen Umgebungen.

Video abspielen


Quelle: habr.com
Купить надежный хостинг для сайтов с защитой от DDoS, VPS VDS серверы 🔥 Купить надежный хостинг для сайтов с защитой от DDoS, VPS VDS серверы | ProHoster