マイクロサービス:結果整合性の処理


22

ユーザーのパスワードを更新する機能があるとします。

[パスワードの更新]ボタンをクリックすると、他の3つのサービスがサブスクライブされているトピックにUpdatePasswordEventが送信されます。

  1. ユーザーのパスワードを実際に更新するサービス
  2. ユーザーのパスワード履歴を更新するサービス
  3. パスワードが変更されたことをユーザーに通知する電子メールを送信するサービス。

結果整合性について私が理解したことから、これらのすべてのサービス(消費者)は同時にイベントを受け取り、それらを個別に処理します。これは、良いシナリオでは、データの整合性につながります。

ただし、サービスがイベントの処理に失敗した場合はどうなりますか?たとえば、突然の切断、データベースエラーなど。これらのトランザクションエラーを処理するための適切なパターン/プラクティスは何ですか?

イベントの処理に失敗した場合、RollbackEventがトピック内に作成され、「ロールバックサービス」がジョブを実行してデータを元に戻すRollbackTopicを作成することを考えていました


11
送信したメールを元に戻すことはできません
:

2
それらはすべて同じサービスの一部である必要があるためです。マイクロサービスはモノリスとは反対です。「物理的に」できるだけ小さく設計する必要があるわけではありません。:これは直接関係ありませんが、あなたはこの質問をお読みくださいし、2つのトップの答えsoftwareengineering.stackexchange.com/questions/339230/...
Walfrat

1
データベース内のユーザーのパスワードを同期的に更新することを検討して、ユーザーに即座にフィードバックを提供し、トピックでパスワードが変更されたというメッセージを送信して他のサービスを非同期にトリガーすることで、メッセージがパスワードが含まれています。
cr3

トランザクションが完了したことをユーザーに伝えるための電子メールですか、または誰か(できればユーザー)がパスワードを変更したことをユーザーに伝えるためのメールです。「それがあなたでなければ、行動する必要があります」。2番目の場合は、できるだけすぐに電子メールを送信してください。
ctrl-alt-delor

回答:


29

結果整合性について私が理解したことから、これらのすべてのサービス(消費者)は同時にイベントを受け取り、それらを個別に処理します。これは、良いシナリオでは、データの整合性につながります。

いいえ、必ずしもそうではありません。私がコメントしたように、送信された電子メールを元に戻すことはできません。そのため、一種の「シーケンス」が必要です。IPC over event-driven data managementは、オーケストレーション1の免除ではありません。

たとえば、前のトランザクションが正常に終了し、メールサービスがその証拠を取得しない限り、メールを送信しないでください。3

ただし、サービスがイベントの処理に失敗した場合はどうなりますか?たとえば、突然の切断、データベースエラーなど。これらのトランザクションエラーを処理するための適切なパターン/プラクティスは何ですか?

挨拶分散コンピューティングの落とし穴。それらは物事を複雑にするものであり、いつものように、それらに対処するための特効薬はありません。

Lost Arkを探して旅を始める前に、まず組織に尋ねることを検討する必要があります。多くの場合、解決策は、組織が現実の世界でこれらの問題にどのように直面するかです

特定のデータが欠落または不完全な場合、全員(部門)は何をしますか?

実装するソリューションを完全に構成するソリューションは、部門ごとに異なることがわかります。

とにかく、ここで私たちが従う戦略で私たちを助けることができるいくつかのプラクティス。

最終的な一貫性

システムが常に一貫した状態であることを保証するのではなく、代わりに、システムが将来のある時点でそれを取得することを受け入れることができます。このアプローチは、特に長期にわたるビジネス運営に役立ちます。

システムが一貫性に達する方法は、システムによって異なります。自動化されたプロセスからある種の人間の介入まで含まれます。たとえば、典型的な後でもう一度試すか、カスタマーサービスに連絡します

すべての操作を中止します

トランザクション補正することにより、システムを一貫した状態に戻します。ただし、これらのトランザクションも失敗する可能性があることを考慮する必要があるため、不整合を解決するのがさらに困難になる可能性があります。また、送信したメールを元に戻すことはできません。

トランザクションの数が少ない場合、補正するトランザクションの数も少ないため、このアプローチは実行可能です。IPCに関係する複数のビジネストランザクションがある場合、それらのそれぞれに対して1つの補償トランザクションを処理するのは困難です。

私達はのために行く場合は取引を補償、我々は見つける回路ブレーカのデザインパターンを非常に有用であることが- と必須の私が言うことをあえて -

分散トランザクション

その考えは、Transaction Managerと呼ばれる全体的な管理プロセスを通じて、単一のトランザクション内の複数のトランザクションにまたがることです。分散トランザクションを処理するための一般的なアルゴリズムは、2フェーズコミットです。

分散トランザクションの主な懸念は、その存続期間中にリソースをロックすることに依存していることであり、私たちが知っているように、トランザクションマネージャーにとっても問題が発生する可能性があります。

場合は、トランザクションマネージャが危険にさらされます、我々は原因メッセージのエンキューに予期しない動作で、その結果、すべての貴様有界コンテキスト間でいくつかのロックで終わることができます。2

分解操作。どうして?

既存のシステムを分解していて、本当に単一のトランザクション境界内に収めたいコンセプトのコレクションを見つけた場合、おそらく最後までそれらを残してください。

サム・ニューマン

上記の議論に沿って、サムは、彼の著書 『Building Microservices』で、最終的に一貫性を確保できない場合は、今すぐ操作を分割しないようにすべきだと述べています。

特定の操作を2つ以上のトランザクションに分割する余裕がない場合、おそらくこれらのトランザクションは同じ境界付きコンテキストに属している、または少なくともモデル化されていないクロスカットコンテキストに属していると言えます。

たとえば、このケースでは、トランザクション#1と#2が互いに密接に関連しており、おそらく両方が同じ境界コンテキストAccountsUsersRegisterに属している可能性があることに気付きます...

同じトランザクションの境界内に両方の操作を配置することを検討してください。これにより、操作全体が処理しやすくなります。また、各トランザクションの重要度のレベルも重要です。おそらく、トランザクション2が失敗した場合、操作全体が危険にさらされることはありません。疑わしい場合は組織に尋ねてください。


1:考えているようなオーケストレーションではありません。私はESBのオーケストレーションについて話しているのではありません。サービスを適切なイベントに反応させることについて話している。

2:分散トランザクションに関するSam Newmanの興味深い意見を見つけることができます。

3:このテーマに関するDavid Parkerの回答を確認してください。


3
非常に良い答えです。分散トランザクションを使用する場合に生じるリスクを考慮することの重要性のみを強調します-主にデッドロックとシステム停止を引き起こすリソースロック。私が約3年前に取り組んだeコマース製品では、システムで使用できるユーザーの数が多いため、システムでエラーが発生しやすいため、DTをメッセージングシステムに置き換える必要がありました。DTの問題は、主にユーザーベースが拡大するときに発生します。
アンディ

7

あなたの場合、3つすべてを一度に処理することはできません。必要なのはプロセスです。これは非常に単純化された例です。

コマンドおよびイベントオーケストレーション

一貫性のあるエンティティで状態変更操作を常に行わなければならないことを知っておくことが重要です。強い一貫性を保証できない場合、マスターレコードで作成する必要があります。

システムは、システムでイベントが発生する前に、最初にトランザクションの安全性を維持して変更を永続化する必要があることを保証する必要があります。これは、発生したイベントが本当に起こったことの確認であることを保証するためです。

プロセスにはいくつかのトリッキーな部分がありますが、次のような明白な部分は無視します。変更したパスワードでユーザーを永続化するときにデータベースサーバーが停止した場合はどうなりますか?UpdatePasswordを再度発行するだけです。ただし、いくつかの部品はあなたが世話をする必要があり、これらは次のとおりです。

  • メッセージの複製の処理、
  • 電子メール送信の処理。

システムでは、プロセスオーケストレーター(PO)は、文字通り用語で内部状態を含む別のエンティティにすぎず、状態間の遷移を許可し、何らかの状態マシンとして効果的に機能します。内部状態のおかげで、メッセージ複製処理を削除できます。

POがNew状態になり、処理されると、POのUserPasswordHasBeenUpdated状態UserPasswordHasBeenUpdated(または動作する状態名)に変わります。POがまだaにUserPasswordHasBeenUpdatedあり、別UserPasswordHasBeenUpdatedのPOが到着した場合、POは重複であることを認識してメッセージを完全に無視します。同様のメカニズムが他の州にも実装されます。

電子メールの実際の送信の処理は少し複雑です。ここには2つのオプションがあります。

  1. せいぜい一度だけ送って、
  2. 少なくとも一度送信してください。

一度だけ送信する

このオプションを使用すると、POがUserPasswordHistoryHasBeenSaved状態に達したときに、状態の変化に対する反応として、電子メールを送信するコマンドがディスパッチされます。システムはUserPasswordHistoryHasBeenSaved、電子メールを送信する前に状態が保持されることを保証します。つまり、重複したメッセージは電子メールの送信を再度トリガーしません。このアプローチを使用すると、POの正しい状態が保存されますが、以降の操作を保証できなくなります。

少なくとも1回送信する

これは私が求めるものです。

それに対するUserPasswordHistoryHasBeenSaved反応として電子メールを保存して送信する代わりに、最初に電子メールを送信しようとします。送信操作が失敗した場合、POの状態は決して変更されUserPasswordHistoryHasBeenSavedず、同じタイプの別のメッセージが処理されます。電子メールの送信は実際に成功したが、新しいUserPasswordHistoryHasBeenSaved状態でPOを保持している間にシステムが失敗した場合、別のメッセージがUserPasswordHistoryHasBeenSaved再び電子メールを送信するコマンドをトリガーし、ユーザーはそれを複数回受信することになります。

あなたの場合、ユーザーが実際に電子メールを受信することを確認したいと思います。そのため、最初のオプションよりも2番目のオプションを選択します。


2

キューイングシステムは、あなたが思うほど壊れやすいものではありません。

3つのプロセスすべてをリレーショナルデータベースに書き込んでいる場合、トランザクションを使用して中間プロセスの障害を処理できます。

最終コミットがなければ、部分的な作業は破棄されます。

キューベースのシステムでは、キューからメッセージを読み取るときに同様のオプションを使用して、中間プロセスの障害を処理できます。

たとえば、Amazon SQSは、読み取られたメッセージを単に非表示にします。最後のDeleteコマンドが送信されない限り、メッセージは再表示されるか、デッドレターキューに入れられます。

さまざまな方法で同様の「トランザクション」を実装でき、処理の成功の確認を受け取るまでメッセージのコピーを本質的に保持します。確認が間に合わない場合。メッセージを再度送信するか、手動で確認するために保管しておくことができます。

これらのエラーメッセージを監視し、関連するメッセージと過去の状態を把握してロールバックを実行する「ロールバックサービス」を作成できる可能性があります。

しかしながら!通常、誤ったメッセージを再送信することをお勧めします。結局、これらはエッジケースである傾向があります。サーバーが壊滅的に失敗したか、特定のメッセージタイプの処理にバグがありました。

エラーが通知されると、サービスを修復し、メッセージを正常に処理できます。システム全体を一貫した状態に戻します。


2

ここであなたが直面しているのは2つの将軍問題です。本質的に:メッセージが受信され、そのメッセージへの応答が発生することをどのようにして確認できますか?多くの場合、完璧なソリューションは存在しません。実際、分散システムでは、メッセージを1回だけ正確に配信することはできません

最初の明白な発言は、パスワードを変更するサービスがパスワード変更イベントを送信する必要があるということです。このように、パスワードが変更された理由に関係なく、パスワードが実際に変更されたときにのみ、パスワード履歴とメール送信サービスがトリガーされます。

実際に問題を解決するために、分散トランザクションを検討するのではなく、少なくとも1回のメッセージ配信とべき等処理の方向に目を向けます。

  • 少なくとも一度は

    パスワード変更イベントがすべてのコンシューマに実際に表示されるようにするには、メッセージを「少なくとも1回」スタイルで消費できる永続的な通信チャネルを使用する必要があります。コンシューマは、メッセージを完全に処理した場合にのみ、メッセージが消費されたことを確認します。たとえば、履歴エントリの書き込み中にパスワード履歴サービスがクラッシュした場合、再起動後に同じパスワード変更イベントを再読み取りして再試行し、それ自体が履歴に書き込まれた後、そのイベントを読み取り専用として認識します。メッセージが承認されるまでメッセージを再送信する機能に基づいて、メッセージキューソリューションを選択する必要があります。

  • べき等

    少なくとも1回の配信を達成した後、消費者が中断されてから再処理される前にメッセージが部分的に処理されると、重複アクションが発生するという問題があります。それは各サービスをdesigning等であるように設計することによって解決されるべきです。実行する書き込みは、悪影響なしで複​​数回発生するか、実行したアクションの独自のストアを保持し、アクションを複数回実行することを避けます。メール送信の場合、たぶん、i等の振る舞いをさせようとするのは価値がなく、たまにメールが2回送信されるだけでも大丈夫でしょう。

いずれにせよ、サービスの作成方法に注意してください。パスワード履歴サービスは本当にパスワード変更サービスから独立している必要がありますか?


1

私は多くの答えに同意しません。

  1. 今すぐ「誰かがパスワードを変更しました。それがあなたなら、何もする必要はありません。パニックにならない場合。」これは、到着すると到着します。
  2. パスワードを変更します。最終的な一貫性はありますが。このセッションでユーザーが行った変更を確認できるようにします。

追加できる一貫性の約束は他にもあります。

  • 変更が時間順に行われるようにします。
  • ユーザーにロールバックが表示されないようにしますが、他のユーザーには変更が表示されない場合があります。
  • 他にもあります

これらの追加の一貫性は、アプリケーションの行為に応じて実装する必要があります。


「履歴を更新する」の意味がわかりませんが、履歴を変更しないでください。DAGを拡張するだけの場合、これにより現在の状態が変化するはずです。彼らは独立していません。もしそうなら、あなたは何が起こったかを反映する履歴に頼ることはできません。(そして最後に、パスワードを保存しないでください。パスワードを保存しない方法を参照してください)


最初にメールを送信できる場合は、アプローチは問題ありません。メールと一緒に何かを送信する必要がある場合。おそらく、一貫性が達成された後にのみ取得できる一種のリンク/データであるため、最初にメールを送信することはできません。それが私がコメントしたことconsider asking the organization first.です。あなたは正しいでしょう。ただし、取り消しできないイベントを条件付けることが重要であることがわかりました。たとえば、エンドユーザーへの通知。ユーザーのデータの実際の状態にある通知は、印象が悪い場合があります。
ライヴ

ただし、この特定のシナリオ(パスワード変更通知)については、このアプローチに同意しました。要件が満たされるとすぐに。
ライヴ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.