Freigeben über


Muster „Ereignissourcing“

Azure

Statt nur den aktuellen Zustand der Daten in einer relationalen Datenbank zu speichern, speichern Sie die vollständige Reihe von Aktionen, die für ein Objekt in einem nur anfügenden Speicher ausgeführt werden. Der Speicher fungiert als Aufzeichnungssystem und kann zum Materialisieren der Domänenobjekte verwendet werden. Dieser Ansatz kann die Leistung, Skalierbarkeit und Auditierbarkeit komplexer Systeme verbessern.

Wichtig

Bei der Ereignisbeschaffung handelt es sich um ein komplexes Muster, das durch die gesamte Architektur durchdringt und Kompromisse einführt, um eine höhere Leistung, Skalierbarkeit und Auditierbarkeit zu erzielen. Sobald Ihr System zu einem Event Sourcing-System wird, werden alle zukünftigen Designentscheidungen durch die Tatsache eingeschränkt, dass es sich um ein Event Sourcing-System handelt. Es gibt eine hohe Kosten für die Migration zu oder von einem Event Sourcing-System. Dieses Muster eignet sich am besten für Systeme, bei denen Leistung und Skalierbarkeit die wichtigsten Anforderungen sind. Die Komplexität, die die Ereignisbeschaffung zu einem System hinzufügt, ist für die meisten Systeme nicht gerechtfertigt.

Kontext und Problem

Die meisten Anwendungen arbeiten mit Daten, und der typische Ansatz besteht darin, dass die Anwendung den neuesten Status der Daten in einer relationalen Datenbank speichert, Daten nach Bedarf einfügt oder aktualisiert. Beispielsweise besteht im herkömmlichen Erstellungs-, Lese-, Aktualisierungs- und Löschmodell (CRUD)-Modell ein typischer Datenprozess darin, Daten aus dem Speicher zu lesen, einige Änderungen daran vorzunehmen und den aktuellen Status der Daten mit den neuen Werten zu aktualisieren – häufig mithilfe von Transaktionen, die die Daten sperren.

Der CRUD-Ansatz ist für die meisten Szenarien einfach und schnell. In Hochlastsystemen hat dieser Ansatz jedoch einige Herausforderungen:

  • Leistung: Da das System skaliert wird, wird die Leistung aufgrund der Konflikte bei Ressourcen und Sperren von Problemen beeinträchtigt.

  • Skalierbarkeit: CRUD-Systeme sind synchron und Datenvorgänge blockieren Updates. Dies kann zu Engpässen und einer höheren Latenz führen, wenn das System geladen wird.

  • Auditierbarkeit: CRUD-Systeme speichern nur den neuesten Status der Daten. Sofern kein Überwachungsmechanismus vorhanden ist, mit dem die Details der einzelnen Vorgänge in einem separaten Protokoll aufgezeichnet werden, geht der Verlauf verloren.

Lösung

Das Ereignissourcingmuster definiert eine Vorgehensweise zur Verarbeitung von Daten, die auf einer Ereignissequenz basiert. Jedes Ereignis wird in einem nur zum Anfügen vorgesehenen Speicher aufgezeichnet. Der Anwendungscode löst Ereignisse aus, die die für das Objekt ausgeführte Aktion zwingend beschreiben. Die Ereignisse werden in der Regel an eine Warteschlange gesendet, bei der ein separater Prozess, ein Ereignishandler, die Warteschlange überwacht und die Ereignisse in einem Ereignisspeicher speichert. Jedes Ereignis stellt eine logische Änderung des Objekts dar, z AddedItemToOrder . B. oder OrderCanceled.

Die Ereignisse werden in einem Ereignisspeicher dauerhaft gespeichert, der als Aufzeichnungssystem (die maßgebliche Datenquelle) für den aktuellen Zustand der Daten fungiert. Zusätzliche Ereignishandler können auf Ereignisse lauschen, an denen sie interessiert sind, und eine entsprechende Aktion ausführen. Consumer könnten z.B. Tasks initiieren, die die Vorgänge in den Ereignissen auf andere Systeme anwenden, oder eine andere verknüpfte Aktion ausführen, die zum Abschließen des Vorgangs erforderlich ist. Beachten Sie, dass der Anwendungscode, der die Ereignisse generiert, von den Systemen abgekoppelt ist, die die Ereignisse abonnieren.

Anwendungen können den Ereignisverlauf zu jeder Zeit lesen. Anschließend können Sie die Ereignisse verwenden, um den aktuellen Status einer Entität zu materialisieren, indem Sie alle Ereignisse wiedergeben und verwenden, die mit dieser Entität zusammenhängen. Dies kann bei Bedarf erfolgen, um bei der Verarbeitung einer Anforderung ein Domänenobjekt zu materialisieren.

Da es relativ teuer ist, Ereignisse zu lesen und wiederzuverwenden, implementieren Anwendungen in der Regel materialisierte Ansichten, schreibgeschützte Projektionen des Ereignisspeichers, die für die Abfrage optimiert sind. Beispielsweise kann ein System eine materialisierte Ansicht aller Kundenbestellungen verwalten, die zum Auffüllen der Benutzeroberfläche verwendet werden. Wenn die Anwendung neue Bestellungen hinzufügt, Artikel in der Bestellung hinzufügt oder entfernt oder Versandinformationen hinzufügt, werden Ereignisse ausgelöst, und ein Handler aktualisiert die materialisierte Ansicht.

Die Abbildung zeigt eine Übersicht über das Muster, einschließlich einiger typischer Implementierungen mit dem Muster, einschließlich der Verwendung einer Warteschlange, eines schreibgeschützten Speichers, der Integration von Ereignissen in externe Anwendungen und Systeme und das Wiedergeben von Ereignissen zum Erstellen von Projektionen des aktuellen Zustands bestimmter Entitäten.

Übersicht und Beispiel des Ereignissourcingmusters

Arbeitsablauf

Im Folgenden wird ein typischer Workflow für dieses Muster beschrieben:

  1. Auf der Präsentationsebene wird ein Objekt aufgerufen, das für das Lesen aus einem schreibgeschützten Speicher verantwortlich ist. Die zurückgegebenen Daten werden verwendet, um die Benutzeroberfläche aufzufüllen.
  2. Auf der Präsentationsebene werden Befehlshandler aufgerufen, um Aktionen wie das Erstellen eines Einkaufswagens oder das Hinzufügen eines Elements zum Warenkorb auszuführen.
  3. Der Befehlshandler ruft den Ereignisspeicher auf, um die historischen Ereignisse für die Entität abzurufen. Beispielsweise kann es alle Einkaufswagenereignisse abrufen. Diese Ereignisse werden im Objekt wiedergegeben, um den aktuellen Status der Entität zu materialisieren, bevor eine Aktion ausgeführt wird.
  4. Die Geschäftslogik wird ausgeführt, und Ereignisse werden ausgelöst. In den meisten Implementierungen werden die Ereignisse in eine Warteschlange oder ein Thema verschoben, um die Ereignishersteller und Ereigniskonsumenten zu entkoppeln.
  5. Ereignishandler lauschen auf Ereignisse, an denen sie interessiert sind, und führen die entsprechende Aktion für diesen Handler aus. Einige typische Ereignishandleraktionen sind:
    1. Schreiben der Ereignisse in den Ereignisspeicher
    2. Aktualisieren eines schreibgeschützten Speichers, der für Abfragen optimiert ist
    3. Integration in externe Systeme

Mustervorteile

Das Ereignissourcingmuster bietet folgende Vorteile:

  • Ereignisse sind unveränderlich und können mit einem Nur-Anfügen-Vorgang gespeichert werden. Benutzeroberflächenelemente, Workflows oder Prozesse, die ein Ereignis auslösen, können weiterhin ausgeführt werden, und Tasks, die die Ereignisse verarbeiten, können im Hintergrund ausgeführt werden. Dieser Prozess kann in Kombination mit der Tatsache, dass während der Verarbeitung von Transaktionen keine Einbußen auftreten, die Leistung und Skalierbarkeit für Anwendungen erheblich verbessern, insbesondere für die Präsentationsebene.

  • Ereignisse sind einfache Objekte, die eine bestimmte durchgeführte Aktion sowie alle zugehörigen Daten beschreiben, die zum Beschreiben der durch das Ereignis repräsentierten Aktion erforderlich sind. Ereignisse aktualisieren einen Datenspeicher nicht direkt. Sie werden nur aufgezeichnet, um zur richtigen Zeit verarbeitet zu werden. Die Nutzung von Ereignissen kann die Implementierung und Verwaltung vereinfachen.

  • Ereignisse haben in der Regel eine Bedeutung für einen Domänenexperten, während die objektrelationale Unverträglichkeit (Object-Relational Impedance Mismatch) dazu führen kann, dass komplexe Datenbanktabellen schwer zu verstehen sind. Tabellen sind künstliche Konstrukte, die den aktuellen Zustand des Systems repräsentieren, nicht die aufgetretenen Ereignisse.

  • Ereignissourcing kann verhindern, dass gleichzeitige Updates Konflikte verursachen, weil Objekte nicht direkt im Datenspeicher aktualisiert werden müssen. Das Domänenmodell muss jedoch weiterhin so entworfen werden, dass es sich selbst vor Anforderungen schützen kann, die zu einem inkonsistenten Zustand führen könnten.

  • Die Nur-Anfügen-Speicherung von Ereignissen erzeugt ein Überwachungsprotokoll, mit dem Handlungen in Bezug auf einen Datenspeicher überwacht werden können. Somit kann der aktuelle Status in Form von materialisierten Sichten oder Projektionen erneut generiert werden, indem die Ereignisse zu einem beliebigen Zeitpunkt erneut wiedergegeben werden. Dies unterstützt zudem die Prüfung und das Debuggen des Systems. Da ausgleichende Ereignisse zum Abbrechen von Änderungen verwendet werden müssen, entsteht zudem ein Protokoll der zurückgenommenen Änderungen. Diese Funktion wäre nicht gegeben, wenn das Modell den aktuellen Zustand speichern würde. Die Liste der Ereignisse kann auch verwendet werden, um die Anwendungsleistung zu analysieren und Trends im Benutzerverhalten zu erkennen. Sie kann zudem verwendet werden, um andere nützliche Geschäftsinformationen zu erhalten.

  • Die Befehlshandler lösen Ereignisse aus, und Aufgaben führen Vorgänge als Reaktion auf diese Ereignisse aus. Diese Abkopplung der Tasks von den Ereignissen sorgt für Flexibilität und Erweiterbarkeit. Tasks kennen den Ereignistyp und die Ereignisdaten, aber nicht den Vorgang, der das Ereignis ausgelöst hat. Darüber hinaus kann jedes Ereignis von mehreren Tasks verarbeitet werden. Dies ermöglicht eine einfache Integration in andere Dienste und Systeme, die nur auf neue vom Ereignisspeicher ausgelöste Ereignisse lauschen. Die Ereignisse beim Ereignissourcing sind jedoch zuweilen sehr spezifisch, und es ist möglicherweise erforderlich, stattdessen spezielle Integrationsereignisse zu generieren.

Die Ereignisbeschaffung wird häufig mit dem CQRS-Muster kombiniert, indem die Datenverwaltungsaufgaben als Reaktion auf die Ereignisse ausgeführt und Ansichten aus den gespeicherten Ereignissen materialisiert werden.

Probleme und Überlegungen

Beachten Sie die folgenden Punkte bei der Entscheidung, wie dieses Muster implementiert werden soll:

  • Letztendliche Konsistenz – Das System wird nur dann konsistent sein, wenn materialisierte Ansichten erstellt oder Projektionen von Daten durch wiedergebende Ereignisse generiert werden. Es gibt eine gewisse Verzögerung zwischen dem Hinzufügen von Ereignissen zum Ereignisspeicher durch eine Anwendung nach der Verarbeitung einer Anforderung, dem Veröffentlichen der Ereignisse und dem Verarbeiten der Ereignisse durch die Consumer. Während dieses Zeitraums können neue Ereignisse im Ereignisspeicher eingegangen sein, die weitere Änderungen an Entitäten beschreiben. Ihre Kunden müssen mit der Tatsache in Ordnung sein, dass Daten letztendlich konsistent sind, und das System sollte so konzipiert sein, dass die Konsistenz in diesen Szenarien berücksichtigt wird.

    Hinweis

    Weitere Informationen zur letztlichen Konsistenz finden Sie unter Data Consistency Primer (Grundlagen der Datenkonsistenz).

  • Versionsverwaltungsereignisse – Der Ereignisspeicher ist die permanente Informationsquelle, sodass die Ereignisdaten niemals aktualisiert werden sollten. Die einzige Möglichkeit, eine Entität zu aktualisieren oder eine Änderung rückgängig zu machen, besteht darin, dem Ereignisspeicher ein Ausgleichsereignis hinzuzufügen. Wenn sich das Schema (anstelle der Daten) der gespeicherten Ereignisse ändern muss, z. B. während einer Migration, kann es schwierig sein, vorhandene Ereignisse im Speicher mit der neuen Version zu kombinieren. Ihre Anwendung muss Änderungen an Ereignisstrukturen unterstützen. Dies kann auf verschiedene Arten erfolgen.

    • Stellen Sie sicher, dass Ihre Ereignishandler alle Versionen von Ereignissen unterstützen. Dies kann eine Herausforderung sein, um zu warten und zu testen. Dies erfordert die Implementierung eines Versionsstempels für jede Version des Ereignisschemas, um sowohl die alten als auch die neuen Ereignisformate beizubehalten.
    • Implementieren Sie einen Ereignishandler zum Behandeln bestimmter Ereignisversionen. Dies kann eine Wartungsabfrage sein, bei der Fehlerkorrekturänderungen möglicherweise über mehrere Handler hinweg vorgenommen werden müssen. Dies erfordert die Implementierung eines Versionsstempels für jede Version des Ereignisschemas, um sowohl die alten als auch die neuen Ereignisformate beizubehalten.
    • Aktualisieren Sie verlaufsbezogene Ereignisse auf das neue Schema, wenn ein neues Schema implementiert wird. Dadurch wird die Unveränderlichkeit von Ereignissen unterbrochen.
  • Ereignisbestellung – Multithreadanwendungen und mehrere Instanzen von Anwendungen können Ereignisse im Ereignisspeicher speichern. Die Konsistenz der Ereignisse im Ereignisspeicher ist von entscheidender Bedeutung, ebenso wie die Reihenfolge der Ereignisse, die eine bestimmte Entität betreffen (die Reihenfolge, in der Änderungen auf eine Entität angewendet werden, wirkt sich auf den aktuellen Zustand aus). Durch Hinzufügen eines Zeitstempels zu jedem Ereignis lassen sich Probleme verhindern. Eine weitere häufige Vorgehensweise besteht darin, jedes Ereignis, das aus einer Anforderung resultiert, mit einem inkrementellen Bezeichner zu kommentieren. Wenn zwei Aktionen versuchen, gleichzeitig Ereignisse für die gleiche Entität hinzuzufügen, kann der Ereignisspeicher ein Ereignis ablehnen, das mit einem vorhandenen Entitätsbezeichner und einem vorhandenen Ereignisbezeichner übereinstimmt.

  • Abfragen von Ereignissen – Es gibt keinen Standardansatz oder vorhandene Mechanismen wie SQL-Abfragen zum Lesen der Ereignisse zum Abrufen von Informationen. Die einzigen Daten, die extrahiert werden können, sind Ereignisströme. Hierbei wird ein Ereignisbezeichner als Kriterium verwendet. Die Ereignis-ID lässt sich in der Regel einzelnen Entitäten zuordnen. Der aktuelle Zustand einer Entität kann nur bestimmt werden, indem alle Ereignisse, die sich auf sie beziehen, im Vergleich zum ursprünglichen Zustand der Entität wiedergegeben werden.

  • Kosten für die Neuerstellen des Zustands für Entitäten – Die Länge jedes Ereignisdatenstroms wirkt sich auf das Verwalten und Aktualisieren des Systems aus. Wenn die Ströme umfangreich sind, kann es sinnvoll sein, in bestimmten Intervallen – z.B. nach einer bestimmten Anzahl von Ereignissen – Momentaufnahmen zu erstellen. Der aktuelle Zustand der Entität kann aus der Momentaufnahme abgerufen werden, indem alle Ereignisse wiedergegeben werden, die nach diesem Zeitpunkt aufgetreten sind. Weitere Informationen zum Erstellen von Momentaufnahmen von Daten finden Sie unter Primäre und untergeordnete Momentaufnahmereplikation.

  • Konflikte – Auch wenn die Ereignisbeschaffung die Wahrscheinlichkeit von widersprüchlichen Aktualisierungen an den Daten minimiert, muss die Anwendung dennoch in der Lage sein, sich mit Inkonsistenzen zu befassen, die aus der letztendlichen Konsistenz und dem Mangel an Transaktionen resultieren. So kann beispielsweise ein Ereignis, das eine Verringerung des Bestands anzeigt, im Datenspeicher ankommen, während eine Bestellung für den betreffenden Artikel eintrifft. In dieser Situation müssen die beiden Vorgänge in Einklang gebracht werden. Entweder muss der Kunde darauf hingewiesen oder eine Nachbestellung erstellt werden.

  • Notwendigkeit für idempotenz - Ereignisveröffentlichung kann mindestens einmal sein, und daher müssen Verbraucher der Ereignisse idempotent sein. Sie dürfen das in einem Ereignis beschriebene Update nicht erneut anwenden, wenn das Ereignis mehr als einmal verarbeitet wird. Mehrere Instanzen eines Consumers können gleichzeitig die Eigenschaften einer Entität aggregieren und verwalten, z. B. die Gesamtzahl der Aufträge. Wenn ein Auftrag eingeht, muss nur einer davon den aggregierten Wert inkrementell erhöhen. Dies ist zwar kein entscheidendes Merkmal des Ereignissourcings, spiegelt jedoch die übliche Implementierungsentscheidung wider.

  • Zirkellogik – Berücksichtigen Sie Szenarien, in denen die Verarbeitung eines Ereignisses die Erstellung eines oder mehrerer neuer Ereignisse umfasst, da dies zu einer endlosen Schleife führen kann.

Verwendung dieses Musters

Verwenden Sie dieses Muster in folgenden Szenarien:

  • Sie möchten eine Absicht, einen Zweck oder einen Grund in den Daten erfassen. Änderungen an einer Kundenentität können z. B. als Reihe von bestimmten Ereignistypen erfasst werden, wie etwa Umgezogen, Konto gekündigt oder Verstorben.

  • Es ist von entscheidender Bedeutung, Aktualisierungskonflikte bei Daten zu minimieren oder vollständig zu vermeiden.

  • Sie möchten auftretende Ereignisse aufzeichnen und wiedergeben, um den Zustand eines Systems wiederherzustellen, Änderungen rückgängig zu machen oder ein Verlaufs- und Überwachungsprotokoll zu pflegen. Wenn beispielsweise ein Task mehrere Schritte umfasst, müssen Sie möglicherweise Aktionen ausführen, um Updates rückgängig zu machen, und dann einige Schritte wiedergeben, um die Daten wieder in einen konsistenten Zustand zu versetzen.

  • Wenn Sie Ereignisse verwenden. Dies ist eine natürliche Betriebsfunktion der Anwendung und erfordert wenig zusätzlichen Aufwand bei Entwicklung und Implementierung.

  • Sie müssen den Prozess der Eingabe oder Aktualisierung von Daten von den Tasks abkoppeln, die zum Anwenden dieser Aktionen erforderlich sind. Diese Änderung kann dazu dienen, die Leistung der Benutzeroberfläche zu verbessern oder Ereignisse auf andere Listener zu verteilen, die eine Aktion ausführen, wenn die Ereignisse auftreten. Sie können z. B. ein Lohnabrechnungssystem mit einer Kostenübermittlungswebsite integrieren. Die als Antwort auf Datenaktualisierungen auf der Website vom Ereignisspeicher aufgerufenen Ereignisse würden dann sowohl von der Website als auch vom Lohnabrechnungssystem verwendet.

  • Wenn Sie mehr Flexibilität benötigen, um das Format der materialisierten Modelle und Entitätsdaten ändern zu können, wenn sich die Anforderungen ändern oder wenn Sie das Muster mit CQRS verwenden, müssen Sie ein Lesemodell oder die Ansichten anpassen, die die Daten verfügbar machen.

  • Wenn Sie das Muster mit CQRS verwenden und die letztliche Konsistenz während der Aktualisierung eines Lesemodells annehmbar ist oder die Leistungsbeeinträchtigung durch das Aktivieren von Entitäten und Daten aus einem Ereignisstrom annehmbar ist.

Dieses Muster ist in den folgenden Situationen eventuell nicht nützlich:

  • Anwendungen, die keine Hyperskalierung oder Leistung erfordern.

  • Kleine oder einfache Domänen, Systeme ohne oder mit nur geringfügiger Geschäftslogik oder Systeme ohne Domäne, die naturgemäß gut mit herkömmlichen CRUD-Datenverwaltungsmechanismen funktionieren.

  • Systeme, in denen Konsistenz und Echtzeitupdates der Datensichten erforderlich sind.

  • Systeme, bei denen nur in geringem Maß Aktualisierungskonflikte bei den zugrunde liegenden Daten auftreten. Dies können z.B. Systeme sein, die Daten eher hinzufügen als aktualisieren.

Workloadentwurf

Ein Architekt sollte evaluieren, wie das Event Sourcing-Pattern im Design seines Workloads verwendet werden kann, um die Ziele und Prinzipien zu erreichen, die in den Säulen des Azure Well-Architected Framework behandelt werden. Zum Beispiel:

Säule So unterstützt dieses Muster die Säulenziele
Zuverlässigkeitsdesignentscheidungen tragen dazu bei, dass Ihre Workload ausfallsicher wird und dass sie nach einem Ausfall wieder in einen voll funktionsfähigen Zustand zurückkehrt. Durch die Erfassung des Änderungsverlaufs in komplexen Geschäftsprozessen kann die Zustandsnachbildung erleichtert werden, wenn Sie Zustandsspeicher wiederherstellen müssen.

- RE:06 Datenpartitionierung
- RE:09 Notfallwiederherstellung
Die Leistungseffizienz hilft Ihrer Workload, Anforderungen effizient durch Optimierungen in Skalierung, Daten und Code zu erfüllen. Dieses Muster kann in der Regel in Kombination mit CQRS, einem geeigneten Domänendesign und strategischen Momentaufnahmen die Workload-Leistung aufgrund der unteilbaren Vorgänge, die ausschließlich Anfügungen zulassen, und der Vermeidung von Datenbanksperren für Schreib- und Lesevorgänge verbessern.

- PE:08 Datenleistung

Berücksichtigen Sie wie bei jeder Designentscheidung alle Kompromisse im Hinblick auf die Ziele der anderen Säulen, die mit diesem Muster eingeführt werden könnten.

Beispiel

Ein Konferenzverwaltungssystem muss die Anzahl der abgeschlossenen Buchungen für eine Konferenz nachvollziehen können. So kann es prüfen, ob noch Sitzplätze vorhanden sind, wenn ein potenzieller Teilnehmer versucht, eine Buchung abzugeben. Das System kann die Gesamtanzahl von Buchungen für eine Konferenz auf mindestens zwei Arten speichern:

  • Das System kann die Informationen zur Gesamtanzahl von Buchungen als separate Entität in einer Datenbank speichern, die Buchungsinformationen enthält. Wenn Buchungen vorgenommen oder storniert werden, kann das System diese Zahl entsprechend erhöhen oder reduzieren. Dieser Ansatz ist in der Theorie sehr einfach, kann aber zu Skalierbarkeitsproblemen führen, wenn eine große Anzahl von Teilnehmern innerhalb kurzer Zeit versucht, Plätze zu buchen. Dies kann beispielsweise am letzten Tag des möglichen Buchungszeitraums der Fall sein.

  • Das System kann Informationen zu Buchungen und Stornierungen in Form von Ereignissen in einem Ereignisspeicher speichern. So kann das System die Anzahl der verfügbaren Plätze durch Wiedergabe dieser Ereignisse berechnen. Dieser Ansatz ist aufgrund der Unveränderlichkeit von Ereignissen besser skalierbar. Das System muss nur Daten aus dem Ereignisspeicher lesen oder an den Ereignisspeicher anfügen können. Ereignisinformationen zu Buchungen und Stornierungen werden niemals geändert.

Das folgende Diagramm veranschaulicht, wie das Platzreservierungs-Subsystem des Konferenzverwaltungssystems mithilfe des Ereignissourcingmusters implementiert werden könnte.

Verwenden von Ereignissourcing zum Erfassen von Informationen zu Platzreservierungen in einem Konferenzverwaltungssystem

Die Aktionssequenz für die Reservierung von zwei Plätzen lautet folgendermaßen:

  1. Die Benutzeroberfläche gibt einen Befehl aus, um Plätze für zwei Teilnehmer zu reservieren. Der Befehl wird von einem separaten Befehlshandler verarbeitet. Dies ist ein Stück Logik, das von der Benutzeroberfläche abgekoppelt ist und für die Verarbeitung von Anforderungen zuständig ist, die als Befehle übermittelt werden.

  2. Eine Entität, die Informationen zu allen Reservierungen für die Konferenz enthält, wird durch Abfragen der Ereignisse erstellt, die Buchungen und Stornierungen beschreiben. Diese Entität wird aufgerufen SeatAvailabilityund ist in einem Domänenmodell enthalten, das Methoden zum Abfragen und Ändern der Daten in der Entität verfügbar macht.

    Einige zu berücksichtigende Optimierungen verwenden Momentaufnahmen (sodass Sie die vollständige Liste der Ereignisse nicht abfragen und wiedergeben müssen, um den aktuellen Status der Entität abzurufen) und eine zwischengespeicherte Kopie der Entität im Arbeitsspeicher zu verwalten.

  3. Der Befehlshandler ruft eine Methode auf, die vom Domänenmodell verfügbar gemacht wurde, um die Reservierungen vorzunehmen.

  4. Die SeatAvailability Entität löst ein Ereignis aus, das die Anzahl der reservierten Arbeitsplätze enthält. Wenn die Entität das nächste Mal Ereignisse anwendet, werden alle Reservierungen verwendet, um zu berechnen, wie viele Arbeitsplätze verbleiben.

  5. Das System fügt das neue Ereignis an die Liste der Ereignisse im Ereignisspeicher an.

Wenn ein Benutzer einen Platz storniert, ist das Verfahren ähnlich – mit einer Ausnahme: Der Befehlshandler gibt einen Befehl aus, der ein Stornierungsereignis generiert und dieses an den Ereignisspeicher anfügt.

Ein Ereignisspeicher bietet nicht nur mehr Raum für Skalierbarkeit, sondern auch einen vollständigen Verlauf bzw. Überwachungspfad der Buchungen und Stornierungen für eine Konferenz. Die Ereignisse im Ereignisspeicher stellen den korrekten Datensatz dar. Es ist nicht notwendig, Aggregate auf andere Weise dauerhaft zu speichern, weil das System ganz einfach die Ereignisse wiedergeben und den Zustand auf einen beliebigen Zeitpunkt wiederherstellen kann.

Nächste Schritte

Die folgenden Muster und Anweisungen können für die Implementierung dieses Musters ebenfalls relevant sein:

  • CQRS-Muster (Command and Query Responsibility Segregation). Der Schreibspeicher, der die permanente Informationsquelle für eine CQRS-Implementierung bereitstellt, basiert oft auf einer Implementierung des Ereignissourcingmusters. Das Muster beschreibt, wie mithilfe separater Schnittstellen die Vorgänge, die Daten in einer Anwendung lesen, von den Vorgängen getrennt werden, die Daten aktualisieren.

  • Muster „Materialisierte Sichten“: Der Datenspeicher, der in einem auf Ereignissourcing basierenden System verwendet wird, eignet sich in der Regel nicht gut für effiziente Abfragen. Ein häufiger Ansatz besteht darin, in regelmäßigen Abständen oder bei Änderung von Daten vorab aufgefüllte Sichten der Daten zu generieren.

  • Muster „Kompensierende Transaktion“: Die vorhandenen Daten in einem Ereignissourcing-Speicher werden nicht aktualisiert. Stattdessen werden neue Einträge hinzugefügt, die den Status der Entitäten auf die neuen Werte übertragen. Um eine Änderung rückgängig zu machen, werden ausgleichende Einträge verwendet, da es nicht möglich ist, die vorherige Änderung rückgängig zu machen. Dieses Muster beschreibt, wie die Ergebnisse eines vorherigen Vorgangs rückgängig gemacht werden können.