イベントソーシングとcqrsに基づいてこのプロジェクトを作成しています。私の書き込みおよび読み取りモデルは異なるデータベース(およびマシン)上にあり、イベントバスを介して接続されています(特に、トランスポートにrabbitmqを使用してMassTransitを使用しています)。
イベントが生成されると、それが私の書き込みモデルに格納され、読み取りモデルがそれをピックアップしてそれに応じてデータベースを更新するキューに公開されます
私がまだ完全に明確にしていないのは、エラーや問題が発生した場合に2つのモデルを同期させる方法です。
たとえば、読み取り側のデータベースがダウンしたり、メッセージキュー自体が停止したりして、書き込み側がこれ以上イベントを発行できなくなる場合があります。
私の最初のアプローチは、すべての集約(私はDDDを使用しています)にバージョン番号があるため、これを使用して、集約インスタンスごとに処理したイベントの数を追跡できます。
たとえば、読み取り側で、ID 8734の私のオブジェクトのバージョン番号が4で、そのオブジェクトの新しいイベントが到着したが、メタデータでバージョン6になっていることが読み取られた場合、読み取りはイベントを逃したことに気付き、メッセージキューを使用して、不足しているものを要求します(この方法では、イベントを順番に処理する問題も実際に解決されます)
欠点は、次のイベントが到着するまでイベントが処理されなかったことをシステムが認識しないことです。 (オブジェクト8734のイベント6が生成されない場合、イベント5が欠落していることに気付くことはありません)
2番目のオプションは、データベースを「ポーリング」して新しいイベントを要求するバックグラウンドプロセッサを作成できますが、これにより、pub/subメッセージングのアイデアが無効になり、読み取りモデルが強制的にイベントを順番に処理するように強制されます。並列処理が許可される(および結果の整合性が遅延する)場合の集約
最後に、読み取り側から、読み取りモデル(またはすべての読み取りモデル)が正しく処理したという確認を受け取るまで、イベントをパブリッシュし続けることができますが、これにより、アプリケーションの書き込み側の応答性が変化します。それが良い戦略なのか、それとも後で私に噛みつくのかわからない
これらの状況にどのように対処しますか?
Greg Youngの Polyglot Data talk には、プルとプッシュの議論が含まれています。
単一のメッセージを分離して扱う場合、Pub/Subは「問題ありません」。低レイテンシでスパースイベントを処理する必要がある場合にも、これは合理的な選択です。
しかし、プルベースのソリューションは、メッセージのシーケンスを処理する場合について考える方がはるかに簡単です。コンシューマーは常に正しい順序でメッセージを取得します。さまざまなコンシューマーは、独自のローカルカーソルを使用して、ストリーム内の位置を追跡し、処理する必要があるイベントのスライスを要求できます。
Pub/subメカニズムは、事実上、notificationメカニズムになり、休止状態のコンシューマ(データをポーリングして、彼らがスリープ状態に戻る前に存在します)。
2016年2月、 Raymond Rutjesが書きました :
DDDヨーロッパの会議で、私が話しているスピーカーは、可能な限りPub/Subを避けているところに気づきました。
グレッグとイヴ・レインハウト(とりわけ)がチャイムします。