DBAtlas · Atlas für Datenbankbetrieb

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.

In DBAtlas öffnen →