Wie Quarkus imperatives und reaktives Programmieren vereint

In diesem Jahr planen wir, die Themen Container ernsthaft voranzutreiben, Cloud-Native Java und Kubernetes. Eine logische Fortsetzung dieser Themen wird die Vorstellung des Frameworks Quarkus sein, das bereits auf Habré behandelt wurde. Der heutige Artikel widmet sich nicht so sehr der Funktionsweise der „subatomaren super schnellen Java“, sondern den Perspektiven, die Quarkus in das Unternehmensumfeld einbringt. Java und die JVM sind nach wie vor äußerst beliebt, aber bei der Arbeit mit serverlosen Technologien und cloud-orientierten Mikrodiensten werden Java und andere Sprachen für die JVM zunehmend seltener verwendet, da sie zu viel Speicherplatz beanspruchen und zu langsam laden, wodurch sie sich schlecht für den Einsatz mit kurzlebigen Containern eignen. Glücklicherweise beginnt sich diese Situation dank Quarkus derzeit zu ändern.

Wie Quarkus imperatives und reaktives Programmieren vereint

Die ultra-schnelle subatomare Java hat ein neues Niveau erreicht!

42 Releases, 8 Monate Community-Arbeit und 177 erstaunliche Entwickler – das Ergebnis ist die Veröffentlichung von

Quarkus 1.0 , einem Release, das einen wichtigen Meilenstein in der Entwicklung des Projekts darstellt und viele coole Funktionen und Möglichkeiten bietet (mehr dazu können Sie lesen inHeute werden wir darüber sprechen, wie Quarkus die Modelle imperativer und reaktiver Programmierung auf der Basis eines einheitlichen reaktiven Kerns kombiniert. Wir beginnen mit einem kurzen Ausflug in die Geschichte und beschäftigen uns dann im Detail mit dem Dualismus des reaktiven Kerns von Quarkus und wie der Ankündigung).

-Entwickler diese Vorteile nutzen können. JavaEreignisgesteuerte Architekturen von Mikrodiensten

serverless, -Funktionen – all dies ist heutzutage, wie man so sagt, im Aufwind. Seit kurzem ist es viel einfacher und zugänglicher geworden, cloud-orientierte Architekturen zu erstellen, jedoch sind Probleme geblieben – insbesondere für Java-Entwickler. So besteht beispielsweise bei serverlosen Funktionen und Mikrodiensten ein akuter Bedarf, die Startzeit zu verkürzen, den Speicherverbrauch zu senken und die Entwicklung angenehmer und komfortabler zu gestalten. In den letzten Jahren hat Java mehrere Verbesserungen hervorgebracht, wie z. B. ein überarbeitetes Ergonomie-Feature für Container und mehr. Dennoch bleibt es schwierig, eine ordnungsgemäße Funktionsweise von Java in einem Container zu erreichen. Deshalb beginnen wir mit einer Betrachtung einiger der internen Herausforderungen von Java, die besonders stark beim Entwickeln von containerorientierten Java-Anwendungen zutage treten. und -Funktionen – all das ist heute, sozusagen, im Aufstieg. In letzter Zeit ist die Erstellung cloud-orientierter Architekturen viel einfacher und zugänglicher geworden, jedoch bestehen die Probleme fort – besonders für Java-Entwickler. Beispielsweise besteht bei serverlosen Funktionen und Mikrodiensten ein akuter Bedarf, die Startzeit zu verkürzen, den Speicherverbrauch zu reduzieren und die Entwicklung angenehmer und benutzerfreundlicher zu gestalten. Java hat in den letzten Jahren einige Verbesserungen eingeführt, wie z. B. die Ergonomie-Funktionalität für Container usw. Doch die ordnungsgemäße Funktion von Java in einem Container bleibt nach wie vor eine Herausforderung. Daher werden wir zunächst einige der internen Herausforderungen von Java betrachten, die sich besonders bei der Entwicklung containerorientierter Java-Anwendungen deutlich zeigen.-Funktionen – all das ist heute, was man nennt, auf dem Vormarsch. Seit kurzem ist die Erstellung von cloudbasierten Architekturen viel einfacher und zugänglicher geworden, jedoch sind die Probleme geblieben – insbesondere für Java-Entwickler. Beispielsweise gibt es bei serverlosen Funktionen und Mikrodiensten einen akuten Bedarf, die Startzeit zu verkürzen, den Speicherbedarf zu reduzieren und die Entwicklung benutzerfreundlicher und angenehmer zu gestalten. In den letzten Jahren hat Java einige Verbesserungen eingebracht, wie die überarbeitete Ergonomie für Container und Ähnliches. Dennoch bleibt es nach wie vor schwierig, Java in einem Container ordnungsgemäß zum Laufen zu bringen. Daher werden wir zunächst einige der internen Herausforderungen von Java betrachten, die sich besonders bei der Entwicklung von containerbasierten Java-Anwendungen scharf zeigen.

Lassen Sie uns zunächst einen Blick auf die Geschichte werfen.

Wie Quarkus imperatives und reaktives Programmieren vereint

Threads und Container

Seit Version 8u131 unterstützt Java mehr oder weniger Container durch Verbesserungen in der Ergonomie-Funktionalität. Insbesondere weiß die JVM jetzt, auf wie vielen Prozessorkernen sie ausgeführt wird und kann die Thread-Pools entsprechend anpassen – in der Regel Fork/Join-Pools. Das ist sicherlich großartig, aber nehmen wir an, wir haben eine traditionelle Webanwendung, die HTTP-Servlets nutzt und in Tomcat, Jetty und ähnlichem läuft. Infolgedessen erzeugt diese Anwendung für jede Anfrage einen separaten Thread und ermöglicht es ihm, diesen Thread während der Wartezeit auf Ein- und Ausgabeoperationen, z. B. beim Zugriff auf Datenbanken, Dateien oder andere Dienste, zu blockieren. Das bedeutet, dass die Größe einer solchen Anwendung nicht von der Anzahl der verfügbaren Kerne abhängt, sondern von der Anzahl gleichzeitiger Anfragen. Darüber hinaus bedeutet dies, dass Quoten oder Limits in Kubernetes bezüglich der Anzahl der Kerne hier nicht wirklich helfen, und letztendlich wird dies zu Drosselung führen.

Speichererschöpfung

Threads sind Speicher. Und interne Container-Speichereinschränkungen sind keineswegs eine Allheilmittel. Fangen Sie einfach an, die Anzahl der Anwendungen und Threads zu erhöhen, und früher oder später werden Sie mit einem kritischen Anstieg der Kontextwechselrate konfrontiert sein, was wiederum zu einer Verschlechterung der Leistung führt. Darüber hinaus, wenn die Anwendung traditionelle Mikrodienst-Frameworks verwendet oder sich mit Datenbanken verbindet oder Caching nutzt oder anderweitig zusätzlichen Speicher verbraucht, benötigen Sie offensichtlich ein Werkzeug, das es Ihnen ermöglicht, in die JVM hinein zu sehen und zu beobachten, wie sie den Speicher verwaltet, ohne dabei die JVM selbst zu zerstören (z. B. XX:+UseCGroupMemoryLimitForHeap). Und selbst wenn die JVM seit Java 9 gelernt hat, cgroups zu erkennen und sich entsprechend anzupassen, bleibt das Reservieren und Verwalten von Speicher eine ziemlich komplexe Angelegenheit.

Quoten und Limits

In Java 11 wurde die Unterstützung für CPU-Quoten (wie PreferContainerQuotaForCPUCount) eingeführt. Kubernetes bietet ebenfalls Unterstützung für Limits und Quoten. Ja, das alles macht Sinn, aber wenn die Anwendung erneut die zugewiesene Quote überschreitet, kommen wir wieder zu der Situation, dass die Größe – wie im Fall traditioneller Java-Anwendungen – nach der Anzahl der Kerne bestimmt wird, wobei für jede Anfrage ein separater Thread zugewiesen wird, was bedeutet, dass all dies nur wenig nützt.
Darüber hinaus lösen die Verwendung von Quoten und Limits oder von Funktionen zur horizontalen Skalierung (Scale-Out) der zugrunde liegenden Kubernetes-Plattform das Problem nicht von selbst. Wir investieren einfach mehr Ressourcen, um das ursprüngliche Problem zu lösen, oder landen schließlich bei einer Übernutzung von Ressourcen. Und wenn es sich um ein stark ausgelastetes System in einer öffentlichen Cloud handelt, beginnen wir nahezu sicher, mehr Ressourcen zu verwenden, als tatsächlich erforderlich sind.

Und was ist mit all dem zu tun?

Einfach ausgedrückt, sollten asynchrone und nicht-blockierende E/A-Bibliotheken sowie Frameworks wie Netty verwendet werden, Vert.x oder Akka. Diese eignen sich aufgrund ihrer reaktiven Natur viel besser für die Arbeit in Containern. Dank der nicht-blockierenden E/A kann der gleiche Thread mehrere gleichzeitige Anfragen gleichzeitig bearbeiten. Während eine Anfrage auf Ergebnisse von E/A wartet, wird der sie bearbeitende Thread freigegeben und kümmert sich um eine andere Anfrage. Und wenn die Ergebnisse der E/A endlich eintreffen, wird die Bearbeitung der ersten Anfrage fortgesetzt. Durch die Abwechselung der Bearbeitung von Anfragen innerhalb desselben Threads lässt sich die Gesamtzahl der Threads reduzieren und der Ressourcenverbrauch bei der Bearbeitung von Anfragen verringern.

Bei nicht-blockierender E/A wird die Anzahl der Kerne zum entscheidenden Parameter, da sie die Anzahl der E/A-Threads bestimmt, die parallel ausgeführt werden können. Bei richtiger Nutzung ermöglicht dies eine effiziente Verteilung der Last auf die Kerne und die Bewältigung höherer Lasten mit weniger Ressourcen.

Wie, und das ist alles?

Nein, es gibt noch mehr. Reaktive Programmierung hilft, Ressourcen besser zu nutzen, hat aber auch ihren Preis. Insbesondere muss der Code gemäß den Prinzipien der Nichtblockierbarkeit umgeschrieben werden und die Blockierung von E/A-Threads muss vermieden werden. Das ist eine ganz andere Entwicklungs- und Ausführungsweise. Und obwohl es hier viele nützliche Bibliotheken gibt, ist es dennoch ein radikaler Wechsel der gewohnten Denkweise.

Zunächst müssen Sie lernen, Code zu schreiben, der asynchron ausgeführt wird. Sobald Sie mit nicht blockierendem Input-Output beginnen, müssen Sie ausdrücklich festlegen, was geschehen soll, wenn eine Antwort auf die Anfrage eingeht. 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 blockierenden Input-Output zu verwenden, benötigen Sie auch nicht blockierende Server und Clients, idealerweise überall. Im Fall von HTTP ist alles einfach, aber es gibt auch Datenbanken und Dateisysteme und vieles mehr.

Obwohl totale durchgängig reaktive Programmierung maximale Effizienz bietet, ist es in der Praxis oft schwierig, einen solchen Wechsel zu verarbeiten. Daher wird die Fähigkeit, reaktiven und imperativen Code zu kombinieren, eine wesentliche Voraussetzung dafür, dass:

  1. Ressourcen in den am stärksten belasteten Bereichen des Softwaresystems effizient genutzt werden;
  2. ein einfacher gestalteter Code in den anderen Teilen verwendet werden kann.

Wir präsentieren Quarkus

Genau das ist die Essenz von Quarkus – die Vereinigung von reaktiven und imperativen Modellen innerhalb einer Laufzeitumgebung.

Quarkus basiert auf Vert.x und Netty, über denen eine Vielzahl von reaktiven Frameworks und Erweiterungen eingesetzt werden, die dem Entwickler helfen sollen. Quarkus ist nicht nur für den Bau von HTTP-Mikroservices gedacht, sondern auch für ereignisgesteuerte Architekturen. Dank seiner reaktiven Natur arbeitet es sehr effizient mit Nachrichtensystemen (Apache Kafka, AMQP usw.).

Die ganze Kunst besteht darin, denselben reaktiven Motor sowohl für imperativen als auch für reaktiven Code zu nutzen.

Wie Quarkus imperatives und reaktives Programmieren vereint

Quarkus bewältigt dies glänzend. Die Wahl zwischen imperativen und reaktiven Ansätzen ist offensichtlich – sowohl für den einen als auch für den anderen das reaktive Kernsystem zu verwenden. Dabei hilft es besonders gut mit schnellem, nicht-blockierendem Code, der nahezu alles verarbeitet, was durch den Ereignis-Loop-Thread (event-loop thread, auch bekannt als IO-Thread) läuft. Aber wenn Sie klassische REST-Anwendungen oder clientseitige Anwendungen haben, hat Quarkus ein imperatives Programmiermodell bereit. Zum Beispiel basiert die Unterstützung von HTTP in Quarkus auf der Verwendung eines nicht-blockierenden reaktiven Engines (Eclipse Vert.x und Netty). Alle HTTP-Anfragen, die Ihre Anwendung erhält, durchlaufen zunächst den Ereignis-Loop (IO-Thread), bevor sie an den Teil des Codes gesendet werden, der die Anfragen steuert. Je nach Ziel kann der Steuerungscode innerhalb eines separaten Threads (dem sogenannten worker thread, verwendet bei Servlets und Jax-RS) aufgerufen werden oder den ursprünglichen Eingabe-/Ausgabe-Stream verwenden (reaktiver Pfad reactive route).

Wie Quarkus imperatives und reaktives Programmieren vereint

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

Auf der Website Quarkus.io es wurden mehrere gute Anleitungen zusammengestellt, die Ihnen den Einstieg in Quarkus erleichtern:

Darüber hinaus haben wir Online-Übungen vorbereitet, um verschiedene Aspekte der reaktiven Programmierung kennenzulernen. Dazu benötigen Sie lediglich einen Browser; keine IDE ist erforderlich, und ein Computer ist nicht unbedingt nötig. Diese Übungen finden Sie unter hier.

Nützliche Ressourcen

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

Wie auf der Website geschrieben wird, Quarkus.io, unterstützt Quarkus die Verwendung des Advanced Message Queuing Protocol ( logischen Kanal, Kubernetes-ein Java-Stack, der auf GraalVM und OpenJDK HotSpot abgestimmt ist und aus den besten Java-Bibliotheken und Standards besteht.

Um Ihnen bei der Einarbeitung zu helfen, haben wir 10 Video-Tutorials ausgewählt, die verschiedene Aspekte von Quarkus und Beispiele für seine Nutzung behandeln:

1. Wir stellen Quarkus vor: Ein Framework der nächsten Generation für Java in 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 reaktive sowie imperativen Programmiermodelle in einer einheitlichen Laufzeitumgebung zu kombinieren, damit Entwickler flexibel beim Arbeiten mit einer Vielzahl von verteilten Anwendungsarchitekturen gestalten können. Erfahren Sie mehr in der Einführungsvorlesung unten.

Video abspielen

2. Quarkus: ultraschnelle subatomare Java

Autor: Burr Sutter
Das Video-Tutorial aus dem DevNation Live Internet-Vortrag zeigt, wie man Quarkus zur Optimierung von Unternehmens-Java-Anwendungen, APIs, Mikrodiensten und serverlosen Funktionen in einer Kubernetes/OpenShift-Umgebung verwenden kann, wodurch sie viel kleiner, schneller und skalierbarer werden.

Video abspielen

3. Quarkus und GraalVM: Hibernate auf ultraschnelle Geschwindigkeiten bringen und auf subatomare Größen komprimieren

Autor: Sanne Grinovero
In der Präsentation erfahren Sie, wie Quarkus entstanden ist, wie es funktioniert und wie es komplexe Bibliotheken wie Hibernate ORM mit nativem GraalVM-kompatibel macht.

Video abspielen

4. Lernen, serverless Anwendungen zu entwickeln

Autor: Marthen Luther
Im folgenden Video wird gezeigt, wie man mit Quarkus eine einfache Java-Anwendung erstellt und sie als serverless Anwendung auf Knative bereitstellt.

Video abspielen

5. Quarkus: Programmieren mit Freude

Autor: Edson Yanaga
Ein Videoleitfaden zur Erstellung Ihres ersten Quarkus-Projekts, der zeigt, warum Quarkus die Herzen der Entwickler erobert.

Video abspielen

6. Java und Container – wie wird ihre gemeinsame Zukunft aussehen?

Autor: Mark Little
Diese Präsentation gibt einen Einblick in die Geschichte von Java und erklärt, warum Quarkus die Zukunft von Java ist.

Video abspielen

7. Quarkus: ultraschnelle subatomare Java

Autor: Dimitris Andreadis
Überblick über die Vorteile von Quarkus, die von Entwicklern geschätzt werden: Einfachheit, ultraschnelle Geschwindigkeiten, beste Bibliotheken und Standards.

Video abspielen

8. Quarkus und subatomare reaktive Systeme

Autor: Clement Escoffier
Durch die Integration mit GraalVM bietet Quarkus eine ultraschnelle Entwicklungserfahrung und eine subatomare Laufzeitumgebung. Der Autor spricht über die reaktive Seite von Quarkus und darüber, wie sie bei der Erstellung reaktiver Anwendungen und Datenstreaming-Anwendungen genutzt werden kann.

Video abspielen

9. Quarkus und schnelle Anwendungsentwicklung in Eclipse MicroProfile

Autor: John Clingan
Durch die Kombination von Eclipse MicroProfile und Quarkus können Entwickler voll funktionsfähige MicroProfile-Containeranwendungen erstellen, die in nur wenigen Millisekunden starten. Das Video erläutert im Detail, wie man eine MicroProfile-Containeranwendung für das Deployment auf der Kubernetes-Plattform codiert.

Video abspielen

10. Java, Version "Turbo"

Autor: Markus Biel
Der Autor zeigt, wie man Quarkus nutzt, um superkompakte und superschnelle Java-Container zu erstellen, die einen echten Durchbruch, insbesondere in serverlosen Umgebungen, ermöglichen.

Video abspielen


Quelle: habr.com
60GB SSD 8Gb DDR4