Grundlagen von Event-Sourcing

the next big thing Golo Roden  –  9 Kommentare

Event-Sourcing ist eine Strategie zum Persistieren von Daten, die häufig im Zusammenhang mit Domain-Driven Design (DDD) und CQRS genannt wird. Tatsächlich sind die Konzepte unabhängig, ergänzen einander aber hervorragend. Wie funktioniert Event-Sourcing?

Das Speichern von Daten folgt üblicherweise dem CRUD-Prinzip. Die vier darin enthaltenen Vorgänge ("CREATE", "READ", "UPDATE" und "DELETE") sind allerdings nicht alle gleichartig, da es sich bei UPDATE und DELETE im Gegensatz zu den anderen um destruktive Vorgänge handelt. Aus dem Grund kommt statt DELETE häufig ein UPDATE mit einem "isDeleted"-Flag zum Einsatz. Doch auch UPDATE verhält sich destruktiv, da die zuvor gespeicherten Daten verloren gehen.

Die grundlegende Idee des Event-Sourcing ist daher, auf den Einsatz von UPDATE und DELETE zu verzichten, und nur die nicht-destruktiven Vorgänge CREATE und READ zu verwenden. Jede fachliche Änderung beziehungsweise jeder fachliche Vorgang wird bei Event-Sourcing mit CREATE als neuer Eintrag in eine stetig wachsende Liste eingetragen, ein sogenanntes Append-Only-Log. Diese Eintrage werden niemals mehr verändert oder gar entfernt.

Auf dem Weg sammelt man bei Event-Sourcing im Lauf der Zeit immer mehr Daten, erhält eine Historie und ein Audit-Log, die sich hervorragend als Grundlage für Reporting und Datenanalysen eignen. Außerdem ermöglichen sie die Reinterpretation der Vergangenheit, um Erkenntnisse zu gewinnen und für die Zukunft zu lernen. Mit dem Fokus auf das Festhalten von fachlichen Vorgängen ist Event-Sourcing weitaus fachlicher getrieben als CRUD, was auf Grund seiner eher technischen Orientierung oftmals als Antipattern gilt.

Event-Sourcing speichert also nicht den aktuellen Zustand, sondern die einzelnen Schritte, die im Lauf der Zeit zum aktuellen Zustand geführt haben. Eine Datenbank, die auf diese Art arbeitet, wird als "Event-Store" bezeichnet.

Das Auslesen des aktuellen Zustands ermöglicht beim Event-Sourcing das sogenannte "Replay". Dabei werden alle zu einem Objekt gespeicherten Einträge in der ursprünglichen Reihenfolge wieder geladen und aggregiert. Das ist allerdings nicht nur für den aktuellen Zustand möglich, sondern auch für den von gestern, vorgestern oder jeden beliebigen anderen Zeitpunkt aus der Vergangenheit.

Was ist Event-Sourcing?

Nachteile von Event-Sourcing

Event-Sourcing bietet also ein fachlicheres Vorgehen, das historische Daten sammelt, ein Audit-Log bietet, eine hervorragende Grundlage für Reporting und Datenanalysen darstellt, und sich als Ausgangsbasis für eine Reinterpretation der Vergangenheit eignet. Das sind gleich mehrere Vorteile im Vergleich zu CRUD, doch wo liegen die Nachteile?

Im Zusammenhang mit Event-Sourcing gibt es fünf grundlegende Herausforderungen, für die es allerdings jeweils Lösungsansätze gibt. Die erste Herausforderung besteht in dem linear steigenden Aufwand des Replays: Je mehr Einträge geladen und aggregiert werden müssen, desto länger dauert ein Replay. Abhilfe schaffen hier die sogenannten "Snapshots", die in regelmäßigen Abständen zusätzlich gespeicherte Zwischenergebnisse darstellen.

  1. Die Grundlage dafür ist die Erkenntnis, dass ein Replay stets deterministisch verläuft, da sich im Event-Store hinterlegte Einträge nicht mehr ändern werden, und es für einen Snapshot zum Zeitpunkt X zudem nicht erheblich ist, ob danach noch weitere Einträge folgen oder nicht. Auf dem Weg muss ein Replay nicht stets bei Null beginnen. Stattdessen genügt es, die seit dem letzten Snapshot hinzugekommenen Einträge auszulesen und zu aggregieren.
  2. Die zweite Herausforderung besteht in dem zunehmenden Speicherbedarf eines Event-Stores, wobei zugleich festzuhalten ist, dass Speicherplatz heute praktisch kaum noch etwas kostet. Außerdem lassen sich alte, nicht mehr benötigte Einträge zur Not auch löschen, sofern ein Snapshot existiert, auf dem ein Replay aufsetzen kann.
  3. Die dritte Herausforderung besteht darin, den aktuellen Zustand nicht nur eines, sondern aller Datensätze zu laden. In dem Fall müsste ein eigener Replay pro Datensatz ausgeführt werden, was rasch zu aufwändig wird. Auch dieses Problem lässt sich mit Snapshots lösen, wobei dafür jeweils nach dem Hinzufügen des neuesten Eintrags ein neuer Snapshot geschrieben werden muss.
  4. Die vierte Herausforderung besteht in der Einhaltung der DSGVO, was zunächst schwierig erscheint, da Event-Sourcing von Haus aus nicht darauf ausgelegt ist, dass einmal gespeicherte Daten noch einmal verändert oder gar gelöscht werden. Allerdings kann man dieses Problem entweder durch Verschlüsseln oder Auslagern von personenbezogenen Daten lösen – wobei sich die Vorgehensweise am individuellen Bedarf orientieren sollte.
  5. Die fünfte und letzte Herausforderung ist das Versionieren von Einträgen im Lauf der Zeit, was sich technisch und fachlich angehen lässt. Die technische Vorgehensweise führt rasch zu neuen Versionen, deren Aussagekraft allerdings nicht besonders hoch ist – die fachliche ist daher in der Regel zu bevorzugen. Trotzdem ist das Versionieren von Einträgen eine der größten und unangenehmsten Herausforderungen beim Event-Sourcing.
Nachteile von Event-Sourcing

CRUD versus Event-Sourcing

Steht man vor der Wahl, CRUD oder Event-Sourcing einzusetzen, helfen die genannten Vor- und Nachteile bei der Entscheidung. Event-Sourcing eignet sich vor allem, wenn eine einfache Nachvollziehbarkeit von Änderungen erforderlich ist. Auch der Bedarf an historischen Daten im Allgemeinen beziehungsweise einem Audit-Log im Speziellen sind gute Indikatoren, wann Event-Sourcing eine gute Wahl darstellt.

Außerdem führt Event-Sourcing zu einem geringeren Konfliktpotenzial bei Änderungen an Daten, da die geschrieben Deltas jeweils nur partielle Daten enthalten: Zwei Einträge in einem Event-Store geraten nur dann miteinander in Konflikt, wenn sie zeitgleich entstehen und sich in Bezug auf die jeweiligen Daten überschneiden – ein in der Praxis weniger häufiger Fall.

Allerdings verfügt auch CRUD über Vorzüge: Wenn weder Semantik noch Fachlichkeit vorliegen, kann Event-Sourcing seine Vorteile nicht ausspielen. Diese Aspekte entstehen nämlich nicht aus dem Nichts, sondern müssen bereits in der Natur der Sache verankert sein. Wenn das nicht gegeben ist, stellt CRUD in der Regel die passendere Wahl dar. Auch das performante Speichern von Rohdaten, bei dem keine Fachlogik auszuführen ist, passt gut zu CRUD.

Beim Aufspüren von Duplikaten und dem Garantieren von Eindeutigkeit spielt CRUD ebenfalls seine Überlegenheit aus. Event-Sourcing erfordert dafür ein deutlich größeren Aufwand. Daher bietet es sich in der Praxis an, CRUD und Event-Sourcing zu kombinieren, wobei CRUD für die eher technischen Aspekte, Event-Sourcing hingegen für die Fachlichkeit eingesetzt wird.

CRUD versus Event-Sourcing

Welche Datenbank für Event-Sourcing?

Sobald man sich entschieden hat, Event-Sourcing zu betreiben, benötigt man eine geeignete Datenbank. Auf den ersten Blick sind die Anforderungen gering, denn mehr als die Unterstützung von "INSERT" und "SELECT" ist nicht erforderlich. Es bedarf keiner aufwändigen Joins, keiner Common-Table-Expressions (CTE) oder sonstiger fortgeschrittener Konstrukte aus SQL. Allenfalls die Unterstützung für Transaktionen ist noch relevant, um beim Speichern von Einträgen eine Alles-oder-Nichts-Semantik abbilden zu können.

Auf den ersten Blick scheinen SQL-Datenbanken jedoch keine gute Wahl für Event-Sourcing zu sein, da alle Einträge eines Event-Stores zwar grundsätzlich eine gemeinsame Struktur aufweisen, sich die Struktur der Fachdaten aber von Anwendung zu Anwendung unterscheidet. Tatsächlich muss ein Event-Store diese Struktur aber nie auswerten, weshalb zum Speichern der fachlichen Daten ein Feld vom Typ BLOB oder JSON völlig genügt. Daher eignen sich SQL-Datenbanken sogar hervorragend.

NoSQL-Datenbanken (wobei in dem Kontext insbesondere Dokumentdatenbanken wie MongoDB von Interesse sind) verfügen an der Stelle über einen Vorteil, da sie schemalos arbeiten und deshalb auf das Verarbeiten unterschiedlicher JSON-Formate ausgelegt sind. Allerdings mangelt es häufig an der Umsetzung der ACID-Kriterien (Atomicity, Consistency, Isolation, Durability) und der Unterstützung von Transaktionen. Selbst in MongoDB, die seit Version 4 ACID-konforme Transaktionen bietet, wirkt die Funktionalität eher wie ein nachgelagerter Gedanke.

Neben SQL- und NoSQL-Datenbanken lässt sich auch auf Spezialsoftware zurückgreifen, beispielsweise die EventStoreDB von Greg Young, der im Jahr 2010 den Begriff "CQRS" (Command Query Responsibility Segregation) geprägt hat. Derartige Systeme sind aber für die meisten Anwendungsfälle zu komplex, entsprechen nicht den bereits in Unternehmen vorhandenen Systemen und sind zudem proprietär. Ihr Einsatz solte daher gut überlegt sein.

Zu guter letzt besteht noch die Option, andere Systeme zweckzuentfremden: Ein typisches Beispiel ist der Message Broker Apache Kafka, der sich als eine Art Event-Store verwenden lässt. Kafka als Event-Store zu benutzen, polarisiert: Den Befürwortern steht eine mindestens ebenso große Gruppe von Entwicklerinnen und Entwicklern gegenüber, die diese Idee grundsätzlich ablehnen. Daher sollte man auch das nur dann machen, wenn man einen dedizierten Spezialfall hat.

Im Großen und Ganzen dürften die meisten Systeme mit dem Einsatz einer klassischen relationalen SQL-Datenbank oder alternativ einer NoSQL-Datenbank wie MongoDB gut bedient sein, zumal die meisten Unternehmen bereits Erfahrung mit diesen Systemen haben.

Welche Datenbank für Event-Sourcing?

DDD und Event-Sourcing kombinieren

Wie eingangs erwähnt, wird Event-Sourcing häufig in Verbindung mit Domain-Driven Design (DDD) genannt. Als gemeinsamer Begriff findet sich in beiden Konzepten das Wort "Event" – bei Event-Sourcing steckt es bereits im Namen, bei DDD findet man es im Zusammenhang mit den sogenannten "Domain-Events".

In beiden Fällen beschreiben Events (beziehungsweise Domain-Events) fachlich relevante Ereignisse, die in der Vergangenheit tatsächlich geschehen sind und daher nicht mehr ungeschehen gemacht werden können, sondern deren Effekte sich bestenfalls durch eine Gegentransaktion kompensieren lassen. Es handelt sich also prinzipiell in beiden Welten um das gleiche Konzept.

Da Domain-Events in der Regel das Ergebnis von Commands sind, bietet es sich an, diese Domain-Events als Einträge in einem Event-Store abzulegen. Ein Replay dient dann dazu, den Zustand des gewünschten Aggregates wiederherzustellen, was die Grundlage für die Verarbeitung weiterer Commands darstellt. Diese Idee passt auch insofern gut zu Event-Sourcing, da es in der Regel nicht einen einzigen Strom von Einträgen gibt, sondern viele kleine, die zu Gruppen zusammengefasst werden – in Bezug auf DDD eben zu Aggregates.

DDD und Event-Sourcing kombinieren

Fazit

Event-Sourcing ist ein spannendes und interessantes Konzept zum Persistieren von Daten. Der Ansatz spielt seine Vorteile in allen Szenarien aus, in denen es um die fachliche Auswertbarkeit von Daten aus der Gegenwart und der Vergangenheit geht. Weniger geeignet ist Event-Sourcing für eine rein technische Datenhaltung wie Forms-over-Data, oder wenn es darum geht, technische Aspekte auf Daten wie Duplikate oder Eindeutigkeit festzustellen.

Daher ist Event-Sourcing kein Ersatz für CRUD, ebenso wie CRUD kein Ersatz für Event-Sourcing ist. Stattdessen ergänzen beide Konzepte einander häufig gut, so dass man je nach Situation entscheiden kann, auf welches Vorgehen man setzen möchte. Unabhängig davon, was man letztlich mehr einsetzt, ist es in jedem Fall vorteilhaft, Event-Sourcing zu kennen, und sei es nur zur Erweiterung des eigenen Horizonts.