Ich entwerfe ein System, das Event Sourcing, CQRS und Microservices verwendet. Ich muss verstehen, dass dies kein ungewöhnliches Muster ist. Ein Schlüsselmerkmal des Dienstes muss die Fähigkeit sein, aus einem Aufzeichnungssystem zu rehydrieren / wiederherzustellen. Microservices erzeugen Befehle und Abfragen auf einem MQ (Kafka). Andere Microservices reagieren (Ereignisse). Befehle und Abfragen werden in S3 zum Zweck der Überwachung und Wiederherstellung beibehalten.
Der aktuelle Denkprozess war, dass wir zum Wiederherstellen des Systems das Ereignisprotokoll aus S3 extrahieren und es einfach an Kafka zurückmelden konnten.
Dies berücksichtigt jedoch nicht die Veränderungen sowohl bei den Herstellern als auch bei den Verbrauchern im Laufe der Zeit. Die Versionierung auf Befehls- / Abfrageebene scheint einen Beitrag zur Lösung des Problems zu leisten, aber ich kann mich nicht mit der Versionierung von Verbrauchern befassen, sodass ich erzwingen kann, dass ein Befehl, der während einer Wiederherstellung empfangen und verarbeitet wird, genau derselbe ist [Version des] Codes, der die Verarbeitung ausführt, da der Befehl zum ersten Mal empfangen wurde.
Gibt es Muster, mit denen ich das lösen kann? Kennt jemand andere Systeme, die für diese Funktion werben?
BEARBEITEN: Ein Beispiel hinzufügen.
Ein "Käufer" sendet eine "Frage" an einen "Verkäufer" auf meiner Auktionsseite. Der Fluss sieht wie folgt aus:
UI -> Web App: POST /question {:text text :to seller-id :from user-id}
Web App -> MQ: SEND {:command send-question :args [text seller-id user-id]}
MQ -< Audit: <command + args appended to log in S3>
MQ -< Questions service: - Record question in DB
- Email seller 'You have a question'
Aufgrund einer neuen Geschäftsanforderung passe ich jetzt den Verbraucher "Fragendienst" an, um die Anzahl aller ungelesenen Fragen beizubehalten. Das DB-Schema wird geändert. Bisher hatten wir keine Ahnung, ob der Verkäufer eine Frage gelesen hat oder nicht. Die letzte Zeile wird:
MQ -< Questions service: - Record question in DB
- Email seller 'You have a question'
- Increment 'unread questions count'
Zwei Befehle sind Probleme, einer vor der Änderung und einer nach der Änderung. Die Anzahl der ungelesenen Fragen entspricht 1.
Das System stürzt ab. Wir haben wiederhergestellt, indem wir die Befehle über den neuen Code wiedergegeben haben. Am Ende der Wiederherstellung beträgt die Anzahl unserer "ungelesenen Fragen" 2. Auch wenn das Ergebnis in diesem erfundenen Beispiel keine Katastrophe ist, ist der wiederhergestellte Zustand nicht der vorherige.
quelle
Antworten:
Erstens ist es wichtig, den Unterschied zwischen Befehlen und Ereignissen zu verstehen und nutzen zu können .
Wie diese Frage kurz und bündig zeigt, sind Befehle Dinge, die wir gerne tun würden, und Ereignisse sind Dinge, die bereits geschehen sind. Ein Befehl führt nicht unbedingt zu einem signifikanten Ereignis im System, aber normalerweise. Beispielsweise kann ein
send message
Befehl abgelehnt werden. In diesem Fall tritt kein Ereignis auf (normalerweise wird ein Fehler nicht als Ereignis in diesem Sinne betrachtet, obwohl wir ihn möglicherweise weiterhin in einem Diagnoseprotokoll protokollieren). Wenn dersend message
Befehl akzeptiert wird, tritt dasmessage sent
Ereignis auf und Ereignisdetails können den Absender, den Empfänger und den Inhalt beschreiben.Wenn wir über den Systemzustand sprechen, diskutieren wir tatsächlich nicht einen Höhepunkt von Befehlen, sondern von Ereignissen. Nur Ereignisse können eine Statusänderung im System verursachen. Angenommen, ich gehe zum örtlichen Publix-Supermarkt und kaufe einen Lottoschein für Florida. Der Befehl lautete "Ticket kaufen" und die Veranstaltung lautete "Ticket ausgestellt". Mein nächster Befehl ist dann zur Lotterie, meine Zahlen für den PowerBall zu ziehen. Die Lotterie wird meinen Befehl ignorieren (aber ich habe keine Kenntnis), und das Ereignis "PowerBall-Nummern ausgewählt" findet unabhängig von meinen Wünschen statt. Wenn meine Zahlen übereinstimmen, passiert mir das Ereignis "Jackpot gewonnen" (und ich glaube, mein Befehl wurde gehört). Wenn nicht, stelle ich fest, dass mein Befehl ignoriert wurde.
Aus historischer Sicht ist die Lotterie nur an einer Teilmenge von Ereignissen interessiert. Die Lotterie kümmert sich nur darum, dass (a) ein Ticket ausgestellt wurde, (b) die Zahlen ausgewählt wurden und (c) der Jackpot gewonnen wurde. Das sind die Gegenstände von Interesse. Der Kauf des Tickets, der Wunsch zu gewinnen usw. sind irrelevant, ebenso wie das, was ich mit meinem Ticket mache, nachdem ich verloren habe. Während sich die reale Welt für weltliche Ereignisse ändert, müssen wir nur die Ereignisse aufzeichnen, die für unser System von Bedeutung sind.
Theoretisch kann unter einer Ereignisbeschaffungstechnik ein Strom von Ereignissen von Beginn der Zeit an wiedergegeben werden, um zum aktuellen Zustand zu gelangen. Dies beruht auf der Annahme, dass die zugrunde liegenden Systembedingungen konstant und deterministisch sind. Diese Annahmen sind jedoch in vielen Systemen nicht gültig. Die mit einem Ereignis verbundenen Daten sowie die Arten von Ereignissen, an denen wir interessiert sind, können sich im Zuge der Weiterentwicklung unserer Computersoftware ändern. Darüber hinaus kann es rechenintensiv sein, den aktuellen Status als Antwort auf jede Abfrage neu zu berechnen. Aus diesem Grund werden häufig Schnappschüsse des Systemstatus erstellt, um bekannte Zeitpunkte darzustellen, zu denen die neuesten Ereignisse hinzugefügt werden können.
Während es immer noch möglich ist, einen Ereignisstrom über mehrere Versionen hinweg wiederzugeben, ist der damit verbundene menschliche Aufwand wahrscheinlich kostenintensiv. Sofern es keinen berechtigten Grund gibt, diese Funktion in das System zu integrieren, sollten Sie Ihr System besser für die Verwendung von Snapshots erstellen.
Beispiel in Frage
In dem in der Frage gegebenen Beispiel ist die Architektur nicht wirklich ereignisbasiert. es ist befehlsbasiert. Durch die Wiedergabe von Befehlen wird der Systemstatus erstellt. Dies ist ein Anti-Muster und sollte behoben werden. Stattdessen sind die primären Ereignisse:
Jedes dieser Ereignisse kann "wiedergegeben" werden, um den aktuellen Status anzuzeigen. Wenn Sie beispielsweise eine Frage stellen, besteht das Systemverhalten möglicherweise darin, dem Verkäufer eine E-Mail zu senden und den
unanswered question
Zähler zu erhöhen . Dieses Verhalten kann geändert werden. Die Tatsache, dass die Frage gestellt wurde, tut dies jedoch nicht. In ähnlicher Weise kann das System denunanswered question
Zähler verringern, wenn der Verkäufer antwortet. Dieses Verhalten ist änderbar, die Tatsache, dass der Verkäufer geantwortet hat, jedoch nicht.Die meisten Event-Sourcing-Systeme berechnen die Anzahl der unbeantworteten Fragen dynamisch, indem sie den spezifischen Ereignisstrom als Antwort auf eine Abfrage wiedergeben.
quelle
Für die Prüfung sicher. Zum Wiederherstellen ? Das ist komisch und verursacht wahrscheinlich Kopfschmerzen.
Wenn Sie Event-Sourcing betreiben möchten, möchten Sie den Status von Ereignissen (Dinge, die in der Vergangenheit passiert sind) und nicht von Befehlen rehydrieren. Dies erspart Ihnen die meisten Probleme, die mit Änderungen an der Befehlsimplementierung verbunden sind. Sie müssen sich nur mit den dauerhaften Statusänderungen befassen.
Die Versionierung ist immer noch ein Problem. Insbesondere möchten Sie sicherstellen, dass Ihre persistierten Ereignisse so geschmeidig wie möglich sind (DTOs-Darstellungen anstelle direkter Serialisierungen der Konzepte in Ihrer Domäne). Wenn Sie Ereignisse aus dem Geschäft lesen, haben Sie die Möglichkeit, sie nach Bedarf zu aktualisieren, bevor Sie sie in den Rehydratisierungszustand versetzen.
quelle