Referenzarchitektur: ereignisgesteuert / CQRS
In einer ereignisgesteuerten Architektur rufen sich Services nicht direkt auf, sondern veröffentlichen Ereignisse in ein Event-Log (z. B. Kafka), und Consumer verarbeiten sie asynchron. Ausgehend vom Aufbau des Event-Backbones geht dieser Baum Schritt für Schritt Event Sourcing (Zustand aus Ereignissen ableiten), Command-/Query-Trennung mit CQRS, Projektion des Lesemodells, Idempotenz, Toleranz für Eventual Consistency und den Trugschluss der „Exactly-once-Zustellung“ durch. Ziel ist ein lose gekoppeltes, skalierbares System, dessen Konsistenz-Kompromisse gut verstanden sind.
Vor welcher Entscheidung stehst du in deiner ereignisgesteuerten Architektur?
Die Grundlage eines ereignisgesteuerten Systems ist ein dauerhaftes Event-Log, das Services über asynchrone Ereignisse verbindet. Baust du noch das Backbone auf, willst du Zustand aus Ereignissen ableiten (Event Sourcing), oder trennst du Lese- und Schreibpfad (CQRS)?
- Ich baue das Event-Backbone auf, das Services verbindet
- Ich will Zustand aus der Ereignishistorie ableiten
- Ich will Lese- und Schreibpfad trennen (CQRS)
Wie baust du die Leseseite in CQRS auf, und wie hoch ist deine Konsistenztoleranz?
In CQRS sind Command- (Schreib-) und Query-Seite (Lese-) getrennt; Schreibereignisse aktualisieren die Projektion, die das Lesemodell speist. Die Kernfrage: Kannst du tolerieren, dass das Lesemodell den Schreibvorgängen hinterherhinkt (Eventual Consistency), oder erwartest du, dass jedes Ereignis genau einmal verarbeitet wird?
- Ich speise das Lesemodell per Projektion aus Ereignissen
- Lesevorgänge müssen aktuell sein; Verzug ist inakzeptabel
- Ich will Ereignisse „genau einmal“ verarbeiten
Empfehlung: ein dauerhaftes Event-Log als Backbone
Im Zentrum einer ereignisgesteuerten Architektur steht ein dauerhaftes, geordnetes Event-Log, in das Producer schreiben und das Consumer in ihrem eigenen Tempo lesen. Dieses Backbone entkoppelt Services zeitlich und in der Skalierung.
Empfehlung: Event Sourcing (Zustand aus Ereignissen ableiten)
Beim Event Sourcing speicherst du nicht den aktuellen Zustand einer Entität, sondern alle (unveränderlichen) Änderungsereignisse, die auf sie angewendet wurden; der aktuelle Zustand ergibt sich durch Anwenden dieser Ereignisse in Reihenfolge. Das liefert eine vollständige Audit-Historie und die Möglichkeit, zu jedem Zeitpunkt der Vergangenheit zurückzukehren.
Empfehlung: Projektion des Lesemodells
In CQRS erzeugt die Schreibseite Ereignisse; eine Projektion hört auf diese Ereignisse und aktualisiert ein abfrageoptimiertes Lesemodell (denormalisierte Sicht). Lesevorgänge werden aus diesem fertigen Modell bedient, vollständig getrennt vom Schreibpfad, und beide Seiten skalieren unabhängig.
Empfehlung: auf Toleranz für Eventual Consistency auslegen
In ereignisgesteuerten/CQRS-Systemen hinkt das Lesemodell den Schreibvorgängen leicht hinterher (Eventual Consistency). Statt das „beseitigen“ zu wollen, lege das Design darauf aus, es zu tolerieren; halte die wenigen Abläufe, die strikte sofortige Konsistenz erfordern, getrennt.
Empfehlung: Idempotenz (der Exactly-once-Trugschluss)
In verteiltem Messaging ist durchgängige „Exactly-once-Zustellung“ in der Praxis ein Trugschluss; Nachrichtenduplikate sind wegen Netzwerk und Wiederholungen unvermeidlich. Das richtige Ziel ist idempotente Verarbeitung: Dasselbe Ereignis zweimal zu verarbeiten muss dasselbe Ergebnis liefern wie einmal.