it-swarm.com.de

Microservices: Umgang mit eventueller Konsistenz

Angenommen, wir haben eine Funktion, die das Passwort eines Benutzers aktualisiert.

Sobald Sie auf die Schaltfläche 'Passwort aktualisieren' klicken, wird ein UpdatePasswordEvent an ein Thema gesendet, in dem 3 andere Dienste abonniert sind:

  1. Ein Dienst, der das Kennwort des Benutzers tatsächlich aktualisiert
  2. Ein Dienst, der den Kennwortverlauf des Benutzers aktualisiert
  3. Ein Dienst, der eine E-Mail sendet, die den Benutzer darüber informiert, dass sein Passwort geändert wurde.

Basierend auf dem, was ich über eventuelle Konsistenz verstanden habe, erhalten alle diese Dienste (Verbraucher) das Ereignis gleichzeitig und verarbeiten sie separat, was in einem guten Szenario dazu führt, dass Daten konsistent sind.

Was ist jedoch, wenn ein Dienst das Ereignis nicht verarbeitet? z.B. plötzliche Trennung, Datenbankfehler usw. Was ist ein gutes Muster/eine gute Vorgehensweise, um diese Transaktionsfehler zu behandeln?

Ich habe darüber nachgedacht, ein RollbackTopic zu erstellen, bei dem, wenn ein Ereignis nicht verarbeitet werden kann, ein RollbackEvent in einem Thema erstellt wird, in dem "Rollback-Dienste" ihre Aufgabe erfüllen und die Daten zurücksetzen

24
mpmp

Basierend auf dem, was ich über eventuelle Konsistenz verstanden habe, erhalten alle diese Dienste (Verbraucher) das Ereignis gleichzeitig und verarbeiten sie separat Ein gutes Szenario führt dazu, dass die Daten konsistent sind.

Nein, nicht unbedingt. Wie ich bereits sagte, können wir eine gesendete E-Mail nicht rückgängig machen, daher benötigen wir immer noch eine Art "Sequenz". [~ # ~] ipc [~ # ~] over ereignisgesteuerte Datenverwaltung ist nicht von der Orchestierung ausgenommen 1.

Beispielsweise sollte die E-Mail erst gesendet werden, wenn die vorherigen Transaktionen erfolgreich abgeschlossen wurden und der E-Mail-Dienst einen Beweis dafür erhält. 3

Was ist jedoch, wenn ein Dienst das Ereignis nicht verarbeitet? z.B. plötzliche Trennung, Datenbankfehler usw. Was ist ein gutes Muster/eine gute Vorgehensweise, um diese Transaktionsfehler zu behandeln?

Begrüßen Sie die Irrtümer des verteilten Rechnens . Sie machen die Dinge kompliziert und wie üblich gibt es keine Silberkugeln, mit denen man umgehen könnte.

Bevor wir uns auf die Suche nach der verlorenen Arche machen, müssen wir zuerst die Organisation fragen. Oft liegt die Lösung in wie die Organisation diesen Problemen in der realen Welt begegnet.

Was jeder (Abteilungen) tut, wenn bestimmte Daten fehlen oder unvollständig sind ?

Wir werden feststellen, dass verschiedene Abteilungen unterschiedliche Lösungen haben, die zusammen die zu implementierende Lösung bilden.

Wie auch immer, hier einige Praktiken, die uns bei der Strategie helfen könnten, zu folgen.

Eventuelle Konsistenz

Anstatt sicherzustellen, dass das System ständig in einem konsistenten Zustand ist, können wir stattdessen akzeptieren, dass das System es irgendwann in der Zukunft erhalten wird. Dieser Ansatz ist besonders nützlich für langlebige Geschäftsvorgänge.

Die Art und Weise, wie das System die Konsistenz erreicht, variiert von System zu System. Dies kann von automatisierten Prozessen bis hin zu menschlichen Eingriffen reichen. Zum Beispiel das typische versuchen Sie es später noch einmal oder das Kontakt mit dem Kundenservice.

Brechen Sie alle Vorgänge ab

Versetzen Sie das System über Ausgleichstransaktionen wieder in einen konsistenten Zustand. Wir müssen jedoch berücksichtigen, dass auch diese Transaktionen fehlschlagen können, was uns zu einem Punkt führen könnte, an dem die Inkonsistenz noch schwieriger zu lösen ist. Auch hier können wir eine gesendete E-Mail nicht rückgängig machen.

Für eine geringe Anzahl von Transaktionen ist dieser Ansatz möglich, da auch die Anzahl von Ausgleichstransaktionen Niedrig ist. Wenn am IPC mehrere Geschäftstransaktionen beteiligt wären, wäre es schwierig, für jede eine Ausgleichstransaktion abzuwickeln.

Wenn wir Transaktionen kompensieren wählen, werden wir feststellen, dass Entwurfsmuster des Leistungsschalters sehr nützlich ist - und obligatorisch, würde ich sagen -

Verteilte Transaktionen

Die Idee ist, mehrere Transaktionen innerhalb einer einzelnen Transaktion durch einen allgemeinen Steuerungsprozess zu umfassen, der als Transaction Manager bekannt ist. Ein gängiger Algorithmus für die Verarbeitung verteilter Transaktionen ist Zwei-Phasen-Festschreibung .

Das Hauptanliegen der verteilten Transaktionen ist, dass sie darauf angewiesen sind, die Ressourcen während ihrer Lebensdauer zu sperren, und wie wir wissen, können auch für den Transaction Manager Probleme auftreten.

Wenn der Transaktionsmanager gefährdet wird, können mehrere Sperren in den verschiedenen begrenzten Kontexten auftreten, was zu unerwartetem Verhalten aufgrund des Einreihens der Nachrichten führt. 2

Zerlegungsvorgänge. Warum?

Wenn Sie ein vorhandenes System zerlegen und eine Sammlung von Konzepten finden, die wirklich innerhalb einer einzelnen Transaktionsgrenze liegen sollen, lassen Sie sie möglicherweise bis zum letzten Mal.

Sam Newman

In Übereinstimmung mit den obigen Argumenten stellt Sam in seinem Buch Building Microservices - fest, dass wir es vermeiden sollten, die Operation jetzt aufzuteilen, wenn wir uns die eventuelle Konsistenz wirklich, wirklich nicht leisten können.

Wenn wir es uns nicht leisten können, bestimmte Operationen in zwei oder mehr Transaktionen aufzuteilen, könnte dies bedeuten, dass diese Transaktionen wahrscheinlich zu demselben begrenzten Kontext oder zumindest zu einem übergreifenden Kontext gehören, der noch modelliert werden muss.

In unserem Fall stellen wir beispielsweise fest, dass die Transaktionen Nr. 1 und Nr. 2 eng miteinander verbunden sind und wahrscheinlich beide zum selben begrenzten Kontext gehören könnten Konten, Benutzer, Registrieren, was auch immer ...

Ziehen Sie in Betracht, beide Vorgänge innerhalb der Grenzen derselben Transaktion zu platzieren. Dies würde die Handhabung des gesamten Vorgangs erleichtern. Wiegen Sie auch den Grad der Kritikalität jeder Transaktion. Wenn Transaktion 2 fehlschlägt, sollte sie wahrscheinlich nicht den gesamten Vorgang gefährden. Im Zweifelsfall wenden Sie sich an die Organisation.


1: Nicht die Art von Orchestrierung, die Sie denken. Ich spreche nicht von ESBs Orchestrierung. Ich spreche davon, die Dienste auf das richtige Ereignis reagieren zu lassen.

2: Vielleicht finden Sie interessante Sam Newmans Meinungen in Bezug auf verteilte Transaktionen.

3: Lesen Sie die Antwort von David Parker zu diesem Thema.

29
Laiv

In Ihrem Fall können Sie nicht alle drei Dinge gleichzeitig verarbeiten. Was Sie brauchen, ist ein Prozess. Hier ist ein extrem vereinfachtes Beispiel:

(Command and event orchestration

Es ist wichtig zu wissen, dass Zustandsänderungsoperationen immer an einer konsistenten Entität durchgeführt werden MÜSSEN. Sofern Sie nicht garantieren können, dass starke Konsistenz , muss dies in einem Stammsatz erfolgen.

Ihr System sollte sicherstellen, dass vor dem Auftreten eines Ereignisses in Ihrem System Änderungen zuerst mit Transaktionssicherheit fortgeführt werden MÜSSEN. Dies soll sicherstellen, dass ein ausgelöstes Ereignis wirklich eine Bestätigung dessen ist, was wirklich passiert ist.

Es gibt einige knifflige Teile des Prozesses, und ich werde die offensichtlichen ignorieren - wie zum Beispiel: Was passiert, wenn Ihr Datenbankserver stirbt, wenn ein Benutzer mit geändertem Kennwort beibehalten wird? Sie geben das UpdatePassword einfach erneut aus. Einige Teile müssen jedoch von Ihnen erledigt werden, und dies sind:

  • umgang mit der Vervielfältigung von Nachrichten,
  • abwicklung des E-Mail-Versands.

In einem System ist Process Orchestrator (PO) nichts anderes als eine andere Entität, die - auch wörtlich - einen internen Zustand enthält und Übergänge zwischen den Zuständen ermöglicht, die effektiv als eine Art Zustandsmaschine fungieren. Dank des internen Status können Sie die Verarbeitung von Nachrichtenduplikationen entfernen.

Wenn sich die Bestellung in einem New -Zustand befindet und UserPasswordHasBeenUpdated verarbeitet, ändert sie ihren Status in UserPasswordHasBeenUpdated (oder den für Sie geeigneten Statusnamen). Sollte sich die Bestellung noch in einem UserPasswordHasBeenUpdated befinden und ein weiteres UserPasswordHasBeenUpdated eintreffen, würde die Bestellung die Nachricht vollständig ignorieren, da sie weiß, dass es sich um eine Duplizierung handelt. Ein ähnlicher Mechanismus würde auch für andere Staaten implementiert.

Der eigentliche Versand der E-Mail ist etwas schwieriger. Hier haben Sie zwei Möglichkeiten:

  1. sende es höchstens einmal,
  2. sende es mindestens einmal.

Senden Sie es höchstens einmal

Mit dieser Option wird bei Erreichen des Status UserPasswordHistoryHasBeenSaved ein Befehl zum Senden einer E-Mail als Reaktion auf die Statusänderung gesendet. Ihr System würde sicherstellen, dass der Status UserPasswordHistoryHasBeenSaved vor dem Senden der E-Mail beibehalten wird, d. H. Eine doppelte Nachricht würde das erneute Senden der E-Mail nicht auslösen. Mit diesem Ansatz stellen Sie sicher, dass der richtige Status für die Bestellung gespeichert wird, können jedoch keinen folgenden Vorgang garantieren.

Senden Sie es mindestens einmal

Dafür würde ich mich entscheiden.

Anstatt UserPasswordHistoryHasBeenSaved zu speichern und die E-Mail als Reaktion darauf zu versenden, versuchen Sie zuerst, die E-Mail zu senden. Wenn der Sendevorgang fehlschlägt, wird der Status der Bestellung niemals in UserPasswordHistoryHasBeenSaved geändert, und eine andere Nachricht desselben Typs wird weiterhin verarbeitet. Sollte das Senden der E-Mail tatsächlich erfolgreich sein, Ihr System jedoch beim Fortbestehen der Bestellung mit ihrem neuen Status UserPasswordHistoryHasBeenSaved ausfallen, würde eine weitere Nachricht des UserPasswordHistoryHasBeenSaved erneut den Befehl zum Senden der E-Mail auslösen E-Mail und der Benutzer hätte es mehrmals erhalten.

In Ihrem Fall möchten Sie sicherstellen, dass der Benutzer die E-Mail tatsächlich erhält. Deshalb würde ich die zweite Option der ersten vorziehen.

7
Andy

Warteschlangensysteme sind nicht ganz so zerbrechlich, wie Sie vielleicht denken.

Wenn wir alle drei Prozesse in eine relationale Datenbank schreiben, verwenden wir möglicherweise eine Transaktion, um einen Fehler bei mittleren Prozessen zu behandeln.

Ohne das endgültige Commit würde die Teilarbeit verworfen.

In einem Warteschlangenbasissystem haben Sie ähnliche Optionen, wenn Sie eine Nachricht aus der Warteschlange lesen, um Fehler während des Prozesses zu behandeln.

Amazon SQS verbirgt beispielsweise einfach gelesene Nachrichten. Wenn kein letzter Löschbefehl gesendet wird, wird die Nachricht erneut angezeigt oder in eine Warteschlange für nicht zustellbare Nachrichten gestellt.

Sie können ähnliche "Transaktionen" auf verschiedene Arten implementieren, indem Sie im Wesentlichen eine Kopie der Nachricht aufbewahren, bis Sie eine Bestätigung über die erfolgreiche Verarbeitung erhalten. Wenn die Bestätigung nicht rechtzeitig eingeht. Sie können die Nachricht erneut senden oder zur manuellen Bearbeitung aufbewahren.

Möglicherweise können Sie einen "Rollback-Dienst" erstellen, der diese fehlerhaften Nachrichten überwacht, über verwandte Nachrichten und den früheren Status Bescheid weiß und einen Rollback durchführt.

Jedoch! Es ist normalerweise besser, die fehlerhaften Nachrichten erneut zu senden. Immerhin handelt es sich in der Regel um Edge-Fälle. Entweder ist ein Server katastrophal ausgefallen oder es gab einen Fehler bei der Behandlung eines bestimmten Nachrichtentyps.

Sobald der Fehler gemeldet wurde, kann der Dienst repariert und die Nachrichten erfolgreich verarbeitet werden. Das System als Ganzes wieder in einen konsistenten Zustand bringen.

2
Ewan

Was Sie hier sehen, ist das Problem mit zwei Generälen . Im Wesentlichen: Wie können Sie sicher sein, dass eine Nachricht empfangen wird und eine Antwort auf diese Nachricht erfolgt? In vielen Fällen gibt es keine perfekte Lösung. Tatsächlich ist es in einem verteilten System oft nmöglich, eine genau einmalige Zustellung zu erhalten von Nachrichten.

Eine erste offensichtliche Bemerkung ist, dass der Dienst, der das Kennwort ändert, das Kennwortänderungsereignis senden sollte. Auf diese Weise werden der Kennwortverlauf und die E-Mail-Versanddienste nur ausgelöst, wenn sich das Kennwort tatsächlich ändert, unabhängig davon, warum es geändert wurde.

Um Ihr Problem tatsächlich zu lösen, würde ich keine verteilten Transaktionen in Betracht ziehen, sondern in Richtung mindestens einmaliger Nachrichtenübermittlung und idempotenter Verarbeitung schauen.

  • Zumindest einmal

    Um sicherzustellen, dass das Kennwortänderungsereignis tatsächlich von allen Verbrauchern gesehen wird, müssen Sie einen dauerhaften Kommunikationskanal verwenden, über den Nachrichten "mindestens einmal" verarbeitet werden können. Die Verbraucher bestätigen eine Nachricht erst dann als verbraucht, wenn sie sie vollständig verarbeitet haben. Wenn beispielsweise der Kennwortverlaufsdienst beim Schreiben eines Verlaufseintrags abstürzt, liest er nach dem Neustart dasselbe Kennwortänderungsereignis erneut und versucht es erneut, wobei dieses Ereignis als schreibgeschützt bestätigt wird, nachdem es selbst in den Verlauf geschrieben wurde. Sie sollten eine Nachrichtenwarteschlangenlösung basierend auf ihrer Fähigkeit auswählen, Nachrichten erneut zu senden, bis sie bestätigt werden.

  • Idempotenz

    Nach Erreichen einer mindestens einmaligen Zustellung besteht das Problem, dass doppelte Aktionen auftreten, wenn eine Nachricht teilweise verarbeitet wurde, bevor der Verbraucher unterbrochen und später erneut verarbeitet wurde. Dies sollte gelöst werden, indem jeder Dienst so gestaltet wird, dass er idempotent ist. Entweder können die von ihm ausgeführten Schreibvorgänge ohne nachteilige Auswirkungen mehrmals ausgeführt werden, oder es wird gespeichert, welche Aktionen ausgeführt wurden, und es wird vermieden, eine Aktion mehrmals auszuführen. Beim Versenden von E-Mails werden Sie feststellen, dass es sich wahrscheinlich nicht lohnt, zu versuchen, dass es sich idempotent verhält, und dass gelegentlich eine E-Mail zweimal gesendet wird.

Seien Sie auf jeden Fall vorsichtig, wie klein Ihre Dienstleistungen sind. Muss Ihr Passwortverlaufsdienst wirklich unabhängig vom Passwortänderungsdienst sein?

2
Joeri Sebrechts

Ich bin mit vielen Antworten nicht einverstanden.

  1. Senden Sie jetzt die E-Mail „Jemand hat Ihr Passwort geändert. Wenn Sie es waren, müssen Sie nichts tun. Wenn nicht Panik. " Dies wird ankommen, wenn es ankommt.
  2. Änder das Passwort. Obwohl Sie letztendlich Konsistenz haben. Sie möchten sicherstellen, dass in dieser Sitzung vom Benutzer vorgenommene Änderungen angezeigt werden.

Es gibt andere Konsistenzversprechen, die Sie hinzufügen können.

  • Stellen Sie sicher, dass Änderungen in der zeitlichen Reihenfolge vorgenommen werden.
  • Stellen Sie sicher, dass ein Benutzer niemals ein Rollback sieht, andere Benutzer die Änderung jedoch möglicherweise immer noch nicht sehen.
  • Da sind andere

Diese zusätzlichen Konsistenzen müssen abhängig von den Taten der Anwendung implementiert werden.


Ich habe keine Ahnung, was Sie unter "Aktualisiert den Verlauf" verstehen, aber bitte ändern Sie den Verlauf niemals. Wenn Sie nur die DAG erweitern, sollte dies zu einer Änderung des aktuellen Status führen. Sie sind nicht unabhängig. Wenn dies der Fall ist, können Sie sich nicht darauf verlassen, dass die Geschichte widerspiegelt, was passiert ist. (und zu guter Letzt keine Passwörter speichern siehe wie man Passwörter nicht speichert )

1
ctrl-alt-delor