Why Reactive: Reaktive Architekturen und ihre Geschichte

Seite 4: Große Datenblöcke in Einheiten zerlegen

Inhaltsverzeichnis

Für die beschriebene Art von Anwendungen sind Streaming-Architekturen, wie Abbildung 5 sie darstellt, zwingend notwendig. Sie legen den Fokus darauf, das Potenzial auf Daten-, Thread- und Netzwerkebene effizienter zu nutzen, um die enormen Datenströme kontinuierlich und ohne Unterbrechung zu verarbeiten. Das ist auch notwendig, denn IoT-Sensoren müssen ihre Daten zeitnah loswerden und können sie nicht zwischenspeichern. Kunden erwarten einen fortlaufenden Video- und Audio-Stream für ein gelungenes Filmerlebnis, Twitter-Nachrichten leben von ihrer Aktualität und lassen sich nicht in eine Warteschleife auslagern.

Der Stil der Streaming-Architektur orientiert sich an Daten, Threads und Netzwerken, sorgt aber vor allem für eine unmittelbare Abnahme und Übertragung von Informationen (Abb. 5.).

(Bild: msg Group)

Um eine effiziente Verarbeitung von Daten zu ermöglichen, gilt es, große Datenblöcke in kleine Einheiten zu zerlegen und in eine eindeutige Reihenfolge zu bringen. Aus den Datenblöcken entstehen geordnete Datenströme (engl. data streams). Für deren Verarbeitung ist in aller Regel ein komplexes Data Stream Processing notwendig: Das bedeutet, dass die Daten zu filtern und zu aggregieren sind. Bei der sukzessiven Ausführung dieser Operationen besteht die Gefahr einer Verstopfung, wonach sich keine weiteren Daten mehr verarbeiten lassen. Ohne eine Parallelisierung der Operationen ist eine kontinuierliche, nicht blockierende Verarbeitung der Datenströme unmöglich.

Das Problem der Parallelisierung lässt sich durch Threads lösen. Software-Plattformen wie Java SE parallelisieren Operationen über sogenannte User Threads. Streng genommen werden die User Threads nicht ganz parallel ausgeführt, denn sie konkurrieren alle um die gleichen Ressourcen, etwa um Speicherplatz oder um die Zeit eines Prozessors. Das hat sich mit der Einführung von Multicore-Prozessoren entschärft, die heute beispielsweise mit 16 Kernen und Hyperthreading-Technologie bis zu 32 Kernel-Threads auf einem Prozessor parallel ausführen. Dabei übernehmen Multithreading-Betriebssysteme die Abbildung von User Threads auf Kernel-Threads.

Seit 2014 stellt Java SE 8 mit den Futures eine User-Thread-Abstraktion zur Verfügung, mit der eine Anwendung Operationen asynchron ausführen kann, etwa eine Netzwerkoperation über HTTP. Allerdings haben Futures einen Nachteil: Die Anwendung muss über Polling das Ende der Operation prüfen und erhält das Ergebnis anschließend über einen einzigen Aufruf, also nicht in Stücken. Das CompleteableFuture, eine Erweiterung des Futures, verbessert das Verhalten nicht wesentlich. Es ermöglicht lediglich, mehrere Futures miteinander zu kombinieren, um eine sinnvolle Synchronisierung zusammenhängender Operationen zu ermöglichen. Und genau hier kommen die Reactive Extensions ins Spiel.

Eric Meyer, früher Professor an der Universität Utrecht und heute Softwarearchitekt bei Microsoft, ist Erfinder der Reactive Extensions und publizierte sie 2012 als Open-Source-Software. Im Zentrum der Reactive Extensions steht das Observer Pattern. Dabei repräsentiert das Observable eine Datenquelle, aus der Datenströme fließen, beispielsweise einen File-, Socket- oder Twitter-Datenstrom. Alle involvierten Observer der Anwendung bekommen die Daten zugeleitet. Damit entfällt das umständliche Polling, denn die Observer erhalten die Daten aktiv per Push.

Pivotal, Netflix und Red Hat haben Meyers Idee 2014 aufgegriffen und in eine Spezifikation mit dem Namen Reactive Streams [12] gegossen. Die Spezifikation besteht aus einer API und aus Regeln, wie die Schnittstelle zu verwenden ist. In den letzten Jahren ist eine Vielzahl von Frameworks aus dem Boden geschossen, die diese API implementieren. Dazu gehören RxJava, Project Reactor aus dem Spring-Ökosystem, Akka oder Vert.x. Diese Frameworks bringen neben der Implementierung der Spezifikation noch zahlreiche Operationen mit, die auf Datenströmen parallel ausführbar sind.