仕事でそれを適用する必要があるかもしれないので、私は最近CQRS/ESに飛び込み始めました。それは多くの問題を解決するので、私たちの場合、それは非常に有望なようです。
私は、ES/CQRSアプリが単純化された銀行のユースケース(出金)にコンテキスト化されたように見える方法についての大まかな理解をスケッチしました。
要約すると、Aさんがお金を引き出す場合:
私が理解したところによると、イベントログはFACTSのログであるため、真実の情報源です。それから、そこからすべての予測を導き出すことができます。
さて、この壮大な計画において私が理解していないのは、この場合に何が起こるかです:
==>バランスが-100eの状態になり、ログに2 MoneyWithdrewEventが含まれています
私が理解しているように、この問題に対処するためのいくつかの戦略があります:
戦略に関する質問:
全体的に、私の理解は同時実行性の処理方法について正しいですか?
注:同じ人がそのような短い時間枠で2倍のお金を引き出すことは不可能であることを理解していますが、詳細に迷わないように、簡単な例を取り上げました
私は、ES/CQRSアプリが単純化された銀行のユースケース(出金)にコンテキスト化されたように見える方法についての大まかな理解をスケッチしました。
これは、イベントソースアプリケーションの完璧な例です。はじめましょう。
毎回コマンドが処理または再試行されます(理解しますが、しばらくお待ちください)。次の手順が実行されます。
Application layer
_のサービスに到達します。Aggregate
を識別し、リポジトリからロードします(この場合、ロードはnew
-Aggregate
インスタンスを実行して、この集約の以前に発行されたすべてのイベントをフェッチし、集約自体に再適用します。集約バージョン後で使用するために保存されます。イベントが適用された後、Aggregateは最終状態になります(つまり、当座預金残高は数値として計算されます)Account::withdrawMoney(100)
のようにAggregate
の適切なメソッドを呼び出し、生成されたイベントを収集します。つまり、MoneyWithdrewEvent(AccountId, 100)
;アカウントに十分なお金がない場合(残高<100)、例外が発生し、すべてが中止されます。それ以外の場合は、次のステップが実行されます。Aggregate
をリポジトリに永続化しようとします(この場合、リポジトリは_Event Store
_です)。これは、version
のAggregate
がAggregate
がロードされたときのものである場合に限り、_Event stream
_に新しいイベントを追加することによって行われます。バージョンが同じでない場合、その後、コマンドが再試行されます-ステップ1に進みます。 version
が同じ場合、イベントは_Event stream
_に追加され、クライアントにはSuccess
ステータスが提供されます。このバージョンチェックは楽観的ロックと呼ばれ、一般的なロックメカニズムです。他の1つのメカニズムは、悲観的ロックで、現在の書き込みが完了するまで他の書き込みが(開始されていないように)ブロックされます。
_Event stream
_という用語は、同じAggregateによって発行されたすべてのイベントを抽象化したものです。
_Event store
_は、最終状態だけでなく、Aggregateへのすべての変更が格納される永続化の一種であることを理解する必要があります。
a)この場合、イベントログは真実のソースではなくなりました。対処方法は?また、撤回を許可することは完全に間違っていましたが、この場合はロックを使用する方が良いですか?
イベントストアは常に真実の源です。
b)ロック==デッドロック、ベストプラクティスに関する洞察はありますか?
楽観的ロックを使用すると、ロックがなく、コマンドを再試行するだけです。
とにかく、ロック!=デッドロック
私は、ES/CQRSアプリが単純化された銀行のユースケース(出金)にコンテキスト化されたように見える方法についての大まかな理解をスケッチしました。
閉じる。問題は、「集計」を更新するロジックが奇妙な場所にあることです。
より一般的な実装では、コマンドハンドラーがメモリに保持するデータモデルと、イベントストア内のイベントのストリームの同期が維持されます。
説明する簡単な例は、コマンドハンドラがイベントストアへの同期書き込みを行い、イベントストアへの接続が書き込みの成功を示している場合にモデルのローカルコピーを更新する場合です。
コマンドハンドラーがイベントストアと再同期する必要がある場合(その内部モデルがストアのモデルと一致しないため)、ストアから履歴を読み込み、独自の内部状態を再構築することでそれを行います。
つまり、矢印2と3(存在する場合)は通常、集約ストアではなくイベントストアに接続されます。
集約バージョンIDをイベントと共にイベントストアに配置します。変更時にバージョンの不一致がある場合、何も起こりません
これのバリエーションは通常、イベントストリームのストリームにappendingではなく、通常、[〜#〜] put [〜#〜]特定のストリーム内の場所。その操作がストアの状態と互換性がない場合、書き込みは失敗し、サービスは適切な失敗モード(クライアントへの失敗、再試行、マージなど)を選択できます。べき等書き込みを使用すると、分散メッセージングの多くの問題が解決しますが、当然、べき等書き込みをサポートするストアが必要です。