IoT Systeme stellen besondere Herausforderungen an IT Architekturen. Die Sensordaten müssen rasch und zuverlässig verarbeitet werden. Durch die sehr hohe Anzahl von Sensoren die regelmäßig und meist in nicht kontrollierbarer Weise Informationen an eine Leitstelle senden, gibt es besondere Anforderungen an die Aggregierung der Daten:
- Hohe Verfügbarkeit
- Hohe Lastspitzen
- Schnelle Verarbeitung der Sensordaten
- Zeitliche Nachvollziebarkeit der Daten
Klassische IT Architekturen können mit einigen dieser Anforderungen nur sehr schwer umgehen. Insbesondere die zeitliche Nachvollziehbarkeit stellt eine Herausforderung dar. Zumeist modelliert man die einzelnen Komponenten (Sensoren, Benutzer) als Objekte die einen bestimmten Zustand annehmen können. Sendet ein Sensor neue Daten, werden diese in der Softwareabbildung aktualisiert - und damit überschrieben! Das Event selbst hat also nur den Selbstzweck die Statusänderung der Software Abbildung auszulösen. Die eigentliche Information, dass dieses Event eingetreten ist geht verloren.
Doch gerade in verteilten, komplexen Systemen mit hoher Concurrency sind gerade die Events die interessanten Informationen. In der Softwareentwicklung gibt es Architekturmuster die diese Dynamik abbilden - Event Sourcing. Hierbei dreht man die Betrachtungsweise um. Die Events werden als die wichtigste Entität betrachtet. Es sind die Events die im System dauerhaft gespeichert werden und nicht (zwangsläufig - doch dazu später mehr) der abgeleitete Status in Form von Objekten aus der Objektorientierten Programmierung. Aus den Events können jedoch die Zustände jederzeit abgeleitet werden.
Events werden in sogenannten Event Stores gespeichert. Die Besonderheit daran ist, dass diese Events niemals im nach hinein modifiziert werden. Sie bilden also die Fakten ab, die in das System eingespielt werden. Der Systemzustand wird immer aus der Reihenfolge der Events abgeleitet. Die gesamten Events werden einfach noch einmal durchlaufen - bis zu dem Zeitpunkt für den der Systemzustand rekonstruiert werden soll. Dadurch ist es möglich den Systemzustand zu einem beliebigen Zeitpunkt wieder herzuleiten. Gerade in sicherheitskritischen Anwendungen ein enormer Vorteil im Vergleich zu klassischen objektorientierten Ansätzen.
Event Stores sind besonders auf das schnelle schreiben von Daten spezialisiert. Weil Daten nicht mehr verändert werden, können diese hoch spezialisiert auf schnelles Schreiben und schnelles Lesen optimiert werden.
Für die Darstellung der Systemzustände in einer Anwendung eignet sich die Event Datenstruktur nicht immer optimal - um genau zu sein in den seltensten Fällen. Um dieses Problem zu lösen kann man neben dem Event Store noch eine zweite Datenquelle einführen - das "Read Modell". Das Read Modell wird aus den Events die im Event Store gespeichert werden abgeleitet und in einem anderen System (oder einer anderen Datenbank) gespeichert. Die Berechnung des Read Modells aus den Events wird über ein weiteres Architektur Pattern durchgeführt - CQRS. Dieses Pattern beschreibt die Ableitung eines (oder mehrerer!) Read Modells aus einem Event Stream - also der laufenden Aktualisierung aus dem Event Store.
Durch die Trennung der Datenmodelle in eine schreiboptimierte (Event Store) und eine auf leseoptimierte (Read Modell) Variante, können die Anforderungen an die hohen Lastspitzen erfüllt werden. Dadurch, dass die Events im Event Store nach dem schreiben niemals aktualisiert werden kann ein Event Store auch sehr gut horizontal skaliert werden - also auf mehrere Computer (oder virtuelle Maschinen) oder allgemeiner formuliert Rechenknoten verteilt werden. Dadurch erreicht man die geforderte hohe Verfügbarkeit solcher Systeme. Gleichzeitig können auch die Events parallel auf mehreren Rechenknoten verteilt gespeichert werden. Damit können neben der hohen Verfügbarkeit auch die hohen Lastspitzen verarbeitet werden. Auch die Ableitung des Read Modells kann auf mehrere Rechenknoten verteilt werden was zu einer schnellen Verarbeitung von Sensordaten führt. Wir können mit dieser Architektur also alle oben genannten Anforderungen erfüllen.
Es gibt allerdings einen Nachteil der nicht verschwiegen werden darf. Zwischen dem empfangen und speichern der Events und der Aktualisierung des Read Modells vergeht Zeit. Es gibt also einen Systemzustand in dem der Event Store und das Read Modell nicht synchron sind, weil die Berechnung des Read-Modells aus dem Event Stream Zeit benötigt. Es ist zwar durch die Architektur garantiert, dass sie wieder synchron werden, aber mit einer gewissen Verzögerung. Dieses Phänomen wird "Eventual Consistency" genannt. Jedoch kann man in der Systemarchitektur die Dauer dieser Verzögerung im allgemeinen recht gut kontrollieren.
In den klassischen objektorientierten Ansätzen hat man das Phänomen übrigens auch, nur wird es dabei nicht explizit klar. Die Verarbeitung von Event Streams passiert dort synchron und nicht verteilt und ist deshalb aufgrund des hohen Synchronisationsaufwands vergleichsweise langsam. D.h. das System skaliert nicht so gut und aktualisiert die Objekte nicht so schnell oder reagiert gar nicht mehr auf hohe Lastspitzen. So wird zwar suggeriert, dass die Daten immer korrekt sind, in Wirklichkeit ist das System aber so langsam, dass es schlicht nicht mit der Aktualisierung der Daten zurecht kommt und damit eine Aktualität der Realität nur suggeriert. ES/CQRS Systeme bilden diesen Fakt einfach ab und machen ihn sichtbar. Und dadurch kann man auch auf diese Verzögerung eingehen und sie explizit behandeln.
Beim Event Sourcing werden also alle Events unmittelbar nach dem Auftreten dauerhaft und unveränderbar gespeichert. Der CQRS Teil der Architektur sorgt dafür das die Event Daten in für die Anwendung nutzbare Lesedaten übersetzt werden. Dabei werden die Events einfach der zeitlichen Reihenfolge nach abgearbeitet. Dieses abarbeiten der Events kann man natürlich auch beliebig oft und mit einem definierten Start- und Endzeitpunkt durchführen. Damit lässt sich der Systemzustand zu jedem beliebigen Zeitpunkt wieder herstellen. Diese Eigenschaft ist in komplexen Systemen eine herausragende Möglichkeit um Fehler in der Software nachvollziehen zu können oder mit den Anwendern eine Zeitreise zu machen um ein besseres Verständnis zu erlangen wie ein System reagieren hätte sollen. Das geht soweit, dass man selbst Fehler die in der Umwandlung der Event Daten in die Lesedaten noch nachträglich beheben kann. Wichtig ist lediglich, dass die Event-Daten korrekt sind. Die daraus abgeleiteten Informationen können immer wieder neu abgeleitet werden. Wir haben diese Möglichkeiten in der Praxis schon mehrere Male genutzt und wollen diese Vorteile nicht mehr missen.
Und siehe da, wir haben alle oben beschriebenen technischen Anforderungen an IoT Plattformen wie
- Hohe Verfügbarkeit
- Hohe Lastspitzen
- Schnelle Verarbeitung der Sensordaten
- Zeitliche Nachvollziehbarkeit der Daten
mit den Bausteinen "Event Sourcing" und "CQRS" abgedeckt. Nachdem wir insbesondere in einer Produktentwicklung bereits viele Jahre mit diesen Entwurfsmustern arbeiten können wir die Praxistauglichkeit dieser Software Architektur uneingeschränkt bestätigen:
IoT ❤ Event Sourcing ;)