© Excellent backgrounds/Shutterstock.com
Wie sich reaktiv im Code widerspiegelt

Von „Enterprise“ zu „Reactive“


Nicht mehr zu übersehen ist das zunehmende Interesse an der Entwicklung reaktiver Anwendungen – spätestens seit Ausgabe 5.2014 des Java Magazins, die es zum Titelthema machte. Viele Entwickler nehmen reaktiv aber bisher nur als vages Versprechen wahr, ohne eine konkrete Vorstellung davon zu haben, was auf Codeebene die wesentlichen Unterschiede zum gängigen Vorgehen, also in der Regel Java EE, ausmacht. Diesen Unterschieden wollen wir uns in diesem Artikel widmen.

Die Grundlagen reaktiver Systeme sind im Reaktiven Manifest [1] beschrieben und in vier Schlagworten schnell zusammengefasst: Ziel ist die Antwortbereitschaft des Systems, erreicht durch Elastizität und Widerstandsfähigkeit, auf Grundlage einer nachrichtenbasierten Kommunikation. Auf die erläuternden Hintergründe der einzelnen Begriffe soll hier nicht eingegangen werden, dafür sei auf das Manifest selbst verwiesen.

Nun liegt es in der Natur eines Manifests, dass es sehr grundsätzliche Forderungen aufstellt, aber darüber vage bleibt, wie diese technisch im Detail umzusetzen sind. Für den Java-Entwickler stellt sich also die Frage, wie sich reaktiv im Code widerspiegelt.

Serverseitige Java-Entwicklung, egal mit welchen Frameworks, spielt sich in der Regel im Java-EE-Umfeld ab. Zumindest das Servlet-API, das ja auch Teil von Java EE ist, wird höchstwahrscheinlich die Grundlage des verwendeten Web- oder REST-Frameworks sein. In der Tat gibt es nun in der reaktiven Entwicklung einige grundlegende Unterschiede dazu. Deren Unkenntnis führt zu Missverständnissen und Verwirrung, daher ist es sinnvoll, sich im Vorhinein mit einigen technischen Aspekten reaktiver Entwicklung vertraut zu machen. Ob bewusst oder nicht, die Erfahrung mit Java EE führt dazu, dass viele Dinge als gegeben angesehen werden, die aber in der reaktiven Welt so nicht mehr vorhanden sind. Es heißt also vor allem: Abschied nehmen von einigen vertrauten Konzepten.

Tschüss, Thread per Request

Das Servlet-API basiert im Grunde auf einem Thread-per-Request-Modell. Jedem Request, der eintrifft, wird ein eigener Thread zugewiesen – sei es ein neuer oder einer aus einem begrenzten Pool. Dieser Thread wird den Request abarbeiten (Abb. 1).

Um moderne Multicore-Prozessoren besser auszunutzen, ergänzen reaktive Systeme das Threadmodell um eine weitere Ebene, mit feinerer Granularität. Unterschiedliche Bibliotheken haben dafür unterschiedliche Ansätze. Prominenteste Vertreter auf der JVM sind Vert.x Verticles [2] und Akkas Aktoren [3]. Als allgemeiner Begriff für die Einheit einer Aufgabe unterhalb des Threadlevels hat sich „Task“ eingebürgert, in gewohnter Bevorzugung des Englischen wird also, unabhängig von der konkret zum Einsatz kommenden Bibliothek, von „Task Level Concurrency“ gesprochen.

Verdeutlichen lässt sich dies am einfachsten anhand einer Webanwendung. Der offensichtlichste Gegensatz zu „Thread per Request“ ist der Event Loop. In einem Event-Loop-Modell gibt es einen einzigen Event-Loop-Thread. Für jeden eingehenden Request wird ein Objekt angelegt, das in einer Queue abgelegt wird. Der Event-Loop-Thread arbeitet in einer Schleife alle diese Objekte ab (Abb. 2).

Reaktive Webframeworks wie Play kombinieren den asynchronen Ansatz des Event-Loop-Modells mit dem JVM-Multi-Threading. Auch hier wird jeder Request zunächst in einer Queue abgelegt. Es arbeitet sich aber nicht ein einzelner Event-Loop-Thread daran ab, sondern ein Pool von Threads (Abb. 3). So wird die Effizienz des Event-Loops genutzt, es werden aber gleichzeitig alle Cores des Systems ausgenutzt. Die Anzahl der verwendeten Threads orientiert sich an der Menge der zur Verfügung stehenden Cores und ist in der Regel höchstens doppelt so groß.

Huehnken-Reactive-1.tif_fmt1.jpgAbb. 1: Thread per Request – zu viele Threads
Huehnken-Reactive-2.tif_fmt1.jpgAbb. 2: Event Loop – nur ein Thread
Huehnken-Reactive-3.tif_fmt1.jpgAbb. 3: m Request x n Threads – mehrere Cores optimal nutzen

Wichtig ist dies für Entwickler unter anderem, weil es im Bezug auf den Umgang mit Threads einige Veränderungen mit sich bringt. Im Thread-per-Request-Modell konnte man während der Verarbeitung eines Requests davon ausgehen, dass der Thread dem Request „exklusiv“ gehört. Viele Programmierer und auch viele Bibliotheken machen sich dies zunutze, indem sie Daten in einem ThreadLocal ablegen. Beispiele hierfür sind der Mapped Diagnostic Context von SLF4J, Spring (z. B. Spring Security, der OpenSession​InViewFilter), Hibernates ThreadLocalSessionContext und viele mehr.

ThreadLocals werden ohnehin schon von vielen kritisch gesehen, da ihre Verwendung eine gewisse Aufmerksamkeit erfordert. Bei dauerhafter Wieder...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang