4Max/shutterstock.com

06. März 2017 / von Dr. Felix Nendzig

Reactive

Programming

in .NET

Welche Unterstützung gibt es für reaktive C#-Entwickler?

Moderne Softwaresysteme müssen heutzutage eine Vielzahl gleichzeitiger Anfragen unabhängiger Nutzer bei stark variierender Last nebenläufig verarbeiten und dabei stets antwortbereit bleiben. Auch bei langwierigen Abfragen oder im Fehlerfall sollten sie performant bleiben und natürlich keinesfalls ausfallen. Das Reactive Manifesto benennt die spezifischen Eigenschaften solcher „reaktiver Systeme“ folgendermaßen:

  • Antwortbereit: Das System antwortet zeitnah, soweit dies überhaupt möglich ist, gegebenenfalls auch nur mit einer Überlastmeldung.
  • Widerstandsfähigkeit: Das System bleibt auch im Fehlerfall noch antwortbereit. Dies erfordert eine Architektur voneinander getrennter Komponenten, so dass einzelne Komponenten ausfallen können, ohne das gesamte System zum Absturz zu bringen.
  • Elastizität: Das System bleibt auch bei stark veränderter Auslastung noch antwortbereit, indem es den Anforderungen gemäß Ressourcen allokiert bzw. freigibt.
  • Nachrichten-basiert: Die Komponenten des Systems kommunizieren untereinander asynchron über Nachrichten. So wird eine lose Kopplung und Location Transparency garantiert. Auch Ausfälle werden als Nachrichten kommuniziert.

Für die Entwicklung reaktiver Systeme nach der Philosophie des Reactive Manifesto gibt es in der .NET-Welt das Framework Akka.NET, welches auf dem Aktor-Modell basiert. Noch einen Schritt weiter geht das Framework Microsoft Orleans mit der Implementierung des “Virtual Actor Model”. Orleans folgt damit dem Ansatz von Akka, bietet dem Entwickler aber laut Microsoft Research erleichterte Programmierung und fordert weniger tiefe Kenntnisse über verteilte Systeme.

Sucht man im Web nach “Reactive Programming .NET”, stellen sich die Reactive Extensions (ReactiveX/Rx) mit Rx.NET als dominante Library in der .NET-Welt dar. Diese ist allerdings eher auf die Verarbeitung von Datenströmen spezialisiert. So gibt es mit ReactiveUI ein MVVM-Framework für die Entwicklung von Benutzeroberflächen für mobile- und Desktop-Apps auf Basis von Rx.NET.

Akka.NET

Akka.NET ist ein Framework für reaktive Programmierung mit einer aktiven Community, das vollständig oder in Teilen in die Anwendung eingebunden werden kann. Akka implementiert das Aktor-Modell, welches als asynchrones, nicht-blockierendes, Ereignis-basiertes Entwicklungsmodell für die Entwicklung parallelisierter, skalierbarer und fehlertoleranter Software geeignet ist. Eingesetzt wird Akka.NET z.B. bei IVC Business Systems und SNL Financial.

Ein Aktor stellt den kleinsten Baustein einer Anwendung dar. Er ist zustandsbehaftet, verfügt ein definiertes Verhalten, eine Mailbox, Kind-Aktoren und eine Supervisor-Strategie. Ein Aktor ist immer Teil eines Aktor-Systems, innerhalb dessen die einzelnen Aktoren zu einer hierarchischen Struktur zusammengefasst sind. Vom Aktor-System erhält man eine Referenz IActorRef auf erzeugte Aktoren. Ein solches Aktor-System ist eine schwergewichtige Struktur, die z.B. bei Bedarf neue Threads erzeugen kann. Zur Bewältigung seiner unterschiedlichen Aufgaben sollte die Anwendung über je ein Aktor-System verfügen. Innerhalb eines Aktor-Systems erfüllt jeder Aktor eine bestimmte Aufgabe und tritt als Supervisor für seine Kind-Aktoren auf, an die er jeweils eine einfache Teilaufgabe delegiert. Aktoren kommunizieren untereinander asynchron über den Austausch von Nachrichten, wobei es keine Rolle spielt, wo sich die einzelnen Aktoren innerhalb eines Netzwerks befinden (Location Transparency).  Da Objekte jeden Typs als Nachrichten verwendet werden können, kann man das Verhalten des Aktors für jeden relevanten Typ speziell implementieren.

Ist die Bearbeitung einer Aufgabe abgeschlossen oder tritt dabei ein Fehler auf, sendet der Aktor eine entsprechende Nachricht an seinen Supervisor. Dieser kann dann passend darauf reagieren und gegebenenfalls den Kind-Aktor beenden, wobei dieser die verwendeten Ressourcen wieder freigibt. 

Microsoft Orleans

Microsoft Orleans ist ein Framework, das von Microsoft Research für die Programmierung skalierbarer, nebenläufiger, Cloud-basierter Systeme entwickelt wurde. Es ist verfügbar ab .NET 4.5.1, seit Januar 2015 Open Source und unterliegt nun der MIT License. Das Framework wird aktiv weiterentwickelt und findet z.B. Verwendung in Microsoft Azure und bei 343 Industries.

Mit dem “Virtual Actor Model” folgt Orleans einem ähnlichen Ansatz wie Akka, um die Entwicklung reaktiver Systeme zu unterstützen. Laut Microsoft Research erfordert das direkte Management der Aktoren in Akka jedoch bessere Kenntnisse verteilter Systeme seitens des Entwicklers, als das bei den virtuellen Aktoren in Orleans der Fall ist. Virtuelle Aktoren können als rein logische Entitäten weder erzeugt noch vernichtet werden und sind somit auch immer adressierbar. Die konkreten Instanzen eines virtuellen Aktors werden Aktivierungen genannt. Ein virtueller Aktoren hat so viele Aktivierungen, wie vom System gerade benötigt werden. Stürzt z.B. ein Server ab, werden die darauf instanziierten Aktivierungen, sofern benötigt, auf einem anderen Server neu instanziiert. Durch die Location Transparency und die automatische Verwaltung der Aktoren werden dem Entwickler in Orleans viele Aufgaben abgenommen und die Komplexität verteilter Systeme im Framework versteckt.

Rx.NET – Reactive Extensions for .NET

Rx ist für die Entwicklung asynchroner, Event-basierter Systeme konzipiert. Neben Rx.NET für C# gibt es mit RxJava, RxJS, RxCpp, Rx.rb, RxPy etc. noch viele weitere Ausprägungen für die Entwicklung in Java, JavaScript, C/C++, Ruby, Python. Die Library findet unter anderem Verwendung bei Microsoft, Netflix (RxJS), GitHub (Rx.NET), wird aktiv weiterentwickelt und unterliegt der Apache License 2.0.

Die Rx-Komponente einer Anwendung verarbeitet einen Strom einlaufender Daten aus einer Datenquelle, z.B. einer Datei, einem Web Service oder UI-Events. Anders als interaktive Komponenten, die aktiv Daten abfragen (pull) und währenddessen nicht antwortbereit sind, verhält sich die reaktive Komponente passiv und ist daher stets antwortbereit. Änderungen an der Quelle, z.B. ein neues Event, werden der Komponente „zugeschoben“ (push).

Das Rx-Paradigma basiert auf der Dualität zwischen dem Subject/Observer- und dem Iterator-Pattern. Unabhängig von der Art der Quelle und des Beobachters implementieren beide jeweils die Interfaces IObservable<T> und IObserver<T>. Durch Aufruf von Subscribe() wird der Beobachter über Änderungen an der Quelle benachrichtigt und kann entsprechend reagieren. Die Subscribe-Methode liefert ein IDisposable zurück, so dass man durch den Aufruf von Dispose() ganz einfach die Beobachtung der Quelle beenden kann. Die Benutzung innerhalb eines using-Blocks ist daher problematisch, da mit Verlassen des Blocks die Beobachtung beendet wird.

Die Stärke des Rx-Ansatzes zeigt sich darin, dass der einlaufende und möglicherweise unabgeschlossene Event-/Datenstrom als IObservable<T> im Folgenden mittels LINQ-Operatoren auf dieselbe Art weiterverarbeitet bzw. gefiltert werden kann wie eine einfache Liste. Wann welche Folgereaktion, die in Subscribe() mitgegeben wurde, mit welcher Priorität ausgeführt wird, lässt sich mit Schedulern steuern.

Um automatisierten Tests von Rx-Komponenten möglichst schnelle Laufzeiten und vor allem deterministische Ergebnisse zu ermöglichen, gibt es den TestScheduler. Dieser erlaubt z.B. mittels emulierter Zeit die Manipulation zeitlicher Abläufe. So kann man Race Conditions vermeiden und auch Code mit Timeouts und verzögerter Ausführung schnell und zuverlässig testen.

Fazit

Sowohl Akka.NET, als auch Microsoft Orleans verfügen über eine aktive Community und werden in großen Projekten erfolgreich eingesetzt. Dabei scheint Akka.NET einen vergleichbaren Funktionsumfang zu haben, wie das Original aus dem Java-Umfeld.

Orleans verspricht eine Vereinfachung der Programmierung gegenüber Akka.NET durch eine höhere Abstraktionsebene des Aktor-Modells. Es stellt sich allerdings die Frage, ob hierdurch nicht auch die direkte Steuerung einzelner Details gegenüber Akka erschwert wird. Interessant ist hierzu folgender Vergleich zwischen Akka.NET und Orleans.

Mit seiner Spezialisierung auf die Verarbeitung von Datenströmen, unterscheidet sich das Anwendungsgebiet von Rx.NET von dem der beiden anderen Frameworks. Für diesen Zweck bietet es allerdings sehr handliche Instrumente an. Selbstverständlich kann Rx.NET auch ergänzend zu Akka.NET oder Orleans eingesetzt werden.

Weiterführende Links

Autor

Weitere Artikel

Das könnte Sie auch interessieren