Angenommen, wir haben eine Funktion, die das Kennwort eines Benutzers aktualisiert.
Sobald Sie auf die Schaltfläche "Passwort aktualisieren" klicken, wird ein UpdatePasswordEvent an ein Thema gesendet, bei dem drei weitere Dienste abonniert sind:
- Ein Dienst, der das Kennwort des Benutzers aktualisiert
- Ein Dienst, der den Kennwortverlauf des Benutzers aktualisiert
- Ein Dienst, der dem Benutzer per E-Mail mitteilt, dass sein Passwort geändert wurde.
Ausgehend von dem, was ich über eventuelle Konsistenz verstanden habe, erhalten alle diese Dienste (Verbraucher) das Ereignis zur gleichen Zeit und verarbeiten sie getrennt, was in einem guten Szenario zu einer Konsistenz der Daten führt.
Was ist jedoch, wenn ein Dienst das Ereignis nicht verarbeiten kann? zB plötzliche Trennung, Datenbankfehler usw. Was ist eine gute Vorgehensweise, um diese Transaktionsfehler zu behandeln?
Ich habe darüber nachgedacht, ein RollbackTopic zu erstellen, bei dem ein RollbackEvent in einem Thema erstellt wird, in dem "Rollback-Services" seine Arbeit erledigen und die Daten zurücksetzen, wenn ein Ereignis nicht verarbeitet werden kann
Antworten:
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 über ereignisgesteuertes Datenmanagement ist nicht von Orchestation 1 ausgenommen .
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
Begrüßen Sie die Irrtümer des Distributed Computing . Sie machen die Dinge kompliziert, und es gibt, wie üblich, keine Silberkugeln, die sich mit ihnen auseinandersetzen könnten.
Bevor wir uns auf die Suche nach der Verlorenen Arche machen, müssen wir zunächst die Organisation fragen. Oft liegt die Lösung darin, wie die Organisation diesen Problemen in der realen Welt begegnet .
Was machen alle (Abteilungen), 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 darstellen.
Wie auch immer, hier einige Übungen, die uns bei der Strategie helfen könnten, zu folgen.
Endgültige 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, ist von System zu System unterschiedlich. Dies kann von automatisierten Prozessen bis zu Eingriffen durch den Menschen reichen. Zum Beispiel der typische Versuch, es später noch einmal zu versuchen, oder der Kontakt mit dem Kundendienst .
Alle Operationen abbrechen
Versetzen Sie das System durch 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 es noch schwieriger ist, die Inkonsistenz zu lösen. Auch hier können wir eine gesendete E-Mail nicht rückgängig machen.
Bei einer geringen Anzahl von Transaktionen ist dieser Ansatz durchführbar, da auch die Anzahl der Kompensationstransaktionen gering ist. Wenn mehrere Geschäftstransaktionen am IPC beteiligt wären, wäre die Abwicklung einer Ausgleichstransaktion für jede dieser Transaktionen eine Herausforderung.
Wenn wir Transaktionen kompensieren wollen , werden wir feststellen , dass das Leistungsschalter-Entwurfsmuster sehr nützlich ist - und obligatorisch, würde ich sagen -
Verteilte Transaktionen
Die Idee ist, mehrere Transaktionen innerhalb einer einzigen Transaktion über einen als Transaction Manager bezeichneten übergreifenden Steuerungsprozess zu erfassen . Ein üblicher Algorithmus für die Verarbeitung verteilter Transaktionen ist das Zwei-Phasen-Festschreiben .
Das Hauptanliegen der verteilten Transaktionen ist, dass sie die Ressourcen während ihrer Lebensdauer sperren müssen, und wie wir wissen, können auch beim Transaction Manager Probleme auftreten.
Wenn der Transaktionsmanager kompromittiert wird, kann dies zu mehreren Sperren in den verschiedenen begrenzten Kontexten führen, was zu unerwartetem Verhalten aufgrund der Einreihung der Nachrichten führt. 2
Zerlegen von Operationen. Warum?
In Übereinstimmung mit den obigen Argumenten hat Sam-in seinem Buch Building Microservices - festgestellt, dass wir es vermeiden sollten, die Operation jetzt aufzuteilen, wenn wir uns die letztendliche Konsistenz wirklich nicht leisten können.
Wenn wir es uns nicht leisten können, bestimmte Vorgänge in zwei oder mehr Transaktionen aufzuteilen, kann es sein, dass diese Transaktionen wahrscheinlich zum selben begrenzten Kontext oder zumindest zu einem übergreifenden Kontext gehören, der modelliert werden muss.
In unserem Fall stellen wir zum Beispiel fest, dass die Transaktionen Nr. 1 und Nr. 2 eng miteinander verbunden sind und wahrscheinlich beide demselben begrenzten Kontext angehören können: Konten , Benutzer , Registrieren , was auch immer ...
Ziehen Sie in Betracht, beide Operationen innerhalb der Grenzen derselben Transaktion zu platzieren. Dies würde die Handhabung der gesamten Operation erleichtern. Gewichtung der Kritikalität jeder Transaktion. Wenn Transaktion 2 fehlschlägt, sollte dies wahrscheinlich nicht den gesamten Vorgang beeinträchtigen. Im Zweifelsfall wenden Sie sich an die Organisation .
1: Nicht die Art von Orchestrierung, die Sie denken. Ich spreche nicht von ESB Orchestation. Ich spreche davon, die Dienste auf das richtige Ereignis reagieren zu lassen.
2: Vielleicht finden Sie interessante Meinungen von Sam Newman zu verteilten Transaktionen.
3: Sehen Sie sich die Antwort von David Parker zu diesem Thema an.
quelle
In Ihrem Fall können Sie nicht alle drei Dinge auf einmal verarbeiten. Was Sie brauchen, ist ein Prozess. Hier ist ein extrem vereinfachtes Beispiel:
Es ist wichtig zu wissen, dass Zustandsänderungsoperationen immer an einer konsistenten Entität durchgeführt werden MÜSSEN. Sofern Sie keine starke Konsistenz garantieren können , muss dies in einem Stammsatz erfolgen.
Ihr System sollte sicherstellen, dass Änderungen vor dem Auslösen eines Ereignisses in Ihrem System immer mit Transaktionssicherheit durchgeführt werden müssen. Dies soll sicherstellen, dass ein ausgelöstes Ereignis wirklich eine Bestätigung dessen ist, was wirklich passiert ist.
Es gibt verschiedene knifflige Teile des Prozesses, und ich werde die offensichtlichen ignorieren - wie zum Beispiel: Was passiert, wenn Ihr Datenbankserver abstürzt, wenn ein Benutzer mit geändertem Kennwort fortbesteht? Sie geben einfach das UpdatePassword erneut aus. Einige Teile müssen jedoch von Ihnen erledigt werden, und dies sind:
In einem System ist Process Orchestrator (PO) nichts anderes als eine andere Entität, die - auch im wörtlichen Sinne - einen internen Zustand enthält und Übergänge zwischen den Zuständen ermöglicht, die quasi als eine Art Zustandsmaschine fungieren. Dank des internen Status können Sie die Verarbeitung von Nachrichten-Duplikaten entfernen.
Wenn sich die Bestellung in einem
New
Status befindet und verarbeitet wirdUserPasswordHasBeenUpdated
, ändert sich ihr Status inUserPasswordHasBeenUpdated
(oder der Name des Status, der für Sie gilt). Sollte sich die Bestellung immer noch in einer befindenUserPasswordHasBeenUpdated
und eine andereUserPasswordHasBeenUpdated
ankommen, würde die Bestellung die Nachricht vollständig ignorieren, da sie weiß, dass es sich um eine Duplikation handelt. Ein ähnlicher Mechanismus würde auch für andere Staaten implementiert.Das eigentliche Versenden der E-Mail ist etwas komplizierter. Hier haben Sie zwei Möglichkeiten:
Senden Sie es höchstens einmal
Mit dieser Option wird, wenn die Bestellung den
UserPasswordHistoryHasBeenSaved
Status erreicht hat, ein Befehl zum Senden einer E-Mail als Reaktion auf die Statusänderung gesendet. Ihr System würde sicherstellen, dass derUserPasswordHistoryHasBeenSaved
Status bestehen bleibt, bevor die E-Mail gesendet wird, dh eine duplizierte Nachricht würde den E-Mail-Versand nicht erneut auslösen. Mit diesem Ansatz stellen Sie sicher, dass der korrekte Status für die Bestellung gespeichert wird, können jedoch keinen nachfolgenden Vorgang garantieren.Senden Sie es mindestens einmal
Dafür würde ich gehen.
Anstatt
UserPasswordHistoryHasBeenSaved
die E-Mail als Reaktion darauf zu speichern und zu versenden, versuchen Sie zunächst, die E-Mail zu senden. Wenn der Sendevorgang fehlschlägt, wird der Status der Bestellung nie auf geändert,UserPasswordHistoryHasBeenSaved
und eine andere Nachricht desselben Typs wird noch verarbeitet. Sollte das Versenden der E-Mail tatsächlich erfolgreich sein, Ihr System jedoch ausfallen, während die Bestellung mit ihrem neuenUserPasswordHistoryHasBeenSaved
Status fortbesteht , würde eine weitere Nachricht vonUserPasswordHistoryHasBeenSaved
erneut den Befehl zum Versenden der E-Mail auslösen, und der Benutzer hätte sie 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.
quelle
Warteschlangensysteme sind nicht so anfällig, wie Sie vielleicht denken.
Wenn wir alle drei Prozesse in eine relationale Datenbank schreiben würden, könnten wir eine Transaktion verwenden, um einen Mid-Process-Fehler zu behandeln.
Ohne die endgültige Zusage würde die Teilarbeit verworfen.
In einem Warteschlangen-Basissystem haben Sie ähnliche Optionen, wenn Sie eine Nachricht aus der Warteschlange lesen, um mittlere Prozessfehler zu behandeln.
Amazon SQS beispielsweise blendet gelesene Nachrichten einfach aus. Wird kein endgültiger Löschbefehl gesendet, 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-Service" erstellen, der diese fehlerhaften Nachrichten überwacht, über verwandte Nachrichten und den vorherigen Status informiert und einen Rollback durchführt.
Jedoch! Es ist normalerweise besser, die fehlerhaften Nachrichten erneut zu senden. Immerhin sind dies eher Randfälle. Entweder ist ein Server katastrophal ausgefallen oder es ist ein Fehler bei der Behandlung eines bestimmten Nachrichtentyps aufgetreten.
Sobald der Fehler gemeldet wurde, kann der Dienst repariert und die Nachrichten erfolgreich verarbeitet werden. Bringen Sie das gesamte System wieder in einen konsistenten Zustand.
quelle
Was Sie hier sehen, ist das Problem der beiden Generäle . 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 oftmals unmöglich, Nachrichten genau einmal zuzustellen.
Eine erste offensichtliche Bemerkung ist, dass der Dienst, der das Passwort ändert, das Passwortänderungsereignis senden sollte. Auf diese Weise werden der Kennwortverlauf und die E-Mail-Sendedienste 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 die Richtung einer mindestens einmaligen Nachrichtenübermittlung und einer idempotenten Verarbeitung schauen.
Mindestens 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 Konsumenten erkennen eine Nachricht erst dann als konsumiert an, wenn sie vollständig verarbeitet wurde. Wenn beispielsweise der Kennwortverlaufsdienst beim Schreiben eines Verlaufseintrags abstürzt, wird nach dem Neustart dasselbe Kennwortänderungsereignis erneut gelesen und ein erneuter Versuch unternommen, wobei dieses Ereignis als schreibgeschützt anerkannt wird, nachdem es selbst in den Verlauf geschrieben wurde. Sie sollten eine Message Queue-Lösung basierend auf ihrer Fähigkeit auswählen, Nachrichten erneut zu senden, bis sie bestätigt werden.
Idempotenz
Nach der 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. Das sollte gelöst werden, indem jeder Dienst so gestaltet wird, dass er idempotent ist. Entweder können die von ihm ausgeführten Schreibvorgänge mehrmals ohne nachteilige Auswirkungen ausgeführt werden, oder es behält seinen eigenen Speicher für die von ihm ausgeführten Aktionen und vermeidet, eine Aktion mehrmals auszuführen. Beim Versenden von E-Mails werden Sie feststellen, dass es sich wahrscheinlich nicht lohnt, ein idempotentes Verhalten zu erreichen, und dass gelegentlich eine E-Mail zweimal gesendet wird.
Seien Sie auf jeden Fall vorsichtig, wie klein Sie Ihre Dienste machen. Muss Ihr Kennwortverlaufsdienst wirklich vom Kennwortänderungsdienst unabhängig sein?
quelle
Ich bin mit vielen Antworten nicht einverstanden.
Es gibt andere Konsistenzversprechen, die Sie hinzufügen können.
Diese zusätzlichen Konsistenzen müssen abhängig von den Taten der Anwendung implementiert werden.
Ich habe keine Ahnung, was Sie unter "Verlauf aktualisieren" verstehen, aber bitte ändern Sie niemals den Verlauf. Wenn Sie nur die DAG erweitern, sollte dies zu einer Änderung des aktuellen Status führen. Sie sind nicht unabhängig. Wenn dem so ist, kann man sich nicht darauf verlassen, dass die Geschichte widerspiegelt, was passiert ist. (und last but not least, Passwörter nicht speichern, siehe wie man Passwörter nicht speichert )
quelle
consider asking the organization first.
. Sie haben wahrscheinlich recht. Es hat sich jedoch als wichtig erwiesen, die Ereignisse zu konditionieren, die nicht rückgängig gemacht werden können. Zum Beispiel Benachrichtigungen an den Endbenutzer. Eine Benachrichtigung, die sich auf den tatsächlichen Zustand der Benutzerdaten bezieht, kann einen schlechten Eindruck hinterlassen.