私は イベントソーシング を最近読んでいて、その背後にあるアイデアが本当に好きですが、次の問題に悩まされています。
コマンド(Webサーバーなど)を受信し、結果としてイベントを生成し、それらを一元化されたストアに格納するN個の同時プロセスがあるとします。また、ストアからのイベントを順次適用することにより、すべての一時的なアプリケーション状態が個々のプロセスのメモリに維持されると仮定します。
ここで、次のビジネスルールがあるとします。個別のユーザーごとに一意のユーザー名が必要です。
2つのプロセスが同じユーザー名Xのユーザー登録コマンドを受け取った場合、両方がXがユーザー名のリストにないことを確認し、ルールは両方のプロセスを検証し、両方が「ユーザー名Xの新しいユーザー」イベントをストアに保存します。 。
ビジネスルールに違反しているため、一貫性のないグローバルな状態になりました(同じユーザー名を持つ2人の異なるユーザーがいます)。
従来のNサーバー<-> 1 RDBMSスタイルのシステムでは、データベースは同期の中心点として使用され、このような不整合を防止するのに役立ちます。
私の質問は、イベントソースシステムは通常どのようにこの問題に取り組むのですか?それらは単にすべてのコマンドを順番に処理しますか(たとえば、ストアに書き込むことができるプロセスの量を1に制限します)?
従来のNサーバー<-> 1 RDBMSスタイルのシステムでは、データベースは同期の中心点として使用され、このような不整合を防止するのに役立ちます。
イベントソースシステムでは、「イベントストア」が同じ役割を果たします。イベントソースオブジェクトの場合、書き込みは、特定のバージョンのイベントストリームへの新しいイベントの追加です。したがって、並行プログラミングと同様に、コマンドを処理するときにその履歴をロックすることができます。イベントソースシステムがより楽観的なアプローチを取ることはより一般的です。以前の履歴を読み込み、新しい履歴を計算してから、比較してスワップします。他のコマンドもそのストリームに書き込んだ場合、比較とスワップは失敗します。そこから、コマンドを再実行するか、コマンドを破棄するか、結果を履歴にマージすることもできます。
Mコマンドを使用するすべてのNサーバーが単一のストリームに書き込もうとすると、競合が大きな問題になります。ここでの通常の答えは、モデル内の各イベントソースエンティティに履歴を割り当てることです。したがって、User(Bob)はUser(Alice)とは異なる履歴を持ち、一方への書き込みが他方への書き込みをブロックすることはありません。
私の質問は、イベントソースシステムは通常どのようにこの問題に取り組むのですか?彼らは単にすべてのコマンドを順番に処理するだけですか?
ビジネスロジックをサービスレイヤーに移動せずにドメインオブジェクト属性の一意の制約を確認するためのエレガントな方法はありますか?
短い回答。多くの場合、その要件を調査すると、(a)他の要件に対する理解が不十分なプロキシであるか、または(b)「ルール」の違反が検出された場合に受け入れられることが明らかになります(例外レポート) 、一定の時間枠内に緩和されている、または頻度が低い(例:クライアントは、使用するコマンドをディスパッチする前に名前が使用可能かどうかを確認できます)。
イベントストアがセット検証(リレーショナルデータベースなど)に優れている場合は、イベントを永続化する同じトランザクションの「一意の名前」テーブルに書き込むことで要件を実装します。
場合によっては、すべてのユーザー名を同じストリームに公開することによってのみ要件を適用できます(これにより、ドメインモデルの一部として、メモリ内の名前のセットを評価できます)。 -この場合、2つのプロセスが更新され、「the」ストリーム履歴を更新しようとしますが、比較およびスワップ操作の1つが失敗し、そのコマンドの再試行で競合を検出できます。
ユーザーがsaga
のように扱われるユーザー登録のためのビジネスプロセス(Domain Driven Design
のコンテキストではCRDT
)を実装できるように思えます。
資源
https://doc.akka.io/docs/akka/current/distributed-data.htmlhttp://archive.is/t0QIx
"Akka分散データを使用したCRDT" https://www.slideshare.net/markusjura/crdts-with-akka-distributed-data 詳細
CmRDT
s-操作ベースのCRDTCvRDT
s-状態ベースのCRTDScala https://github.com/akka/akka-samples/tree/master/akka-sample-distributed-data-scala のコード例。多分 "ショッピングカート」が最適です。