セットアップに関する簡単な説明:
RDBMS(私の場合はPostgres)を使用して、「基本的な」イベントストア/イベントソーシングアプリケーションを実装しようとしています。イベントは、のようなだけでいくつかの基本的なフィールドを持つ汎用イベントですeventtime
、location
、action
、XMLとしてフォーマット。この一般的な構造により、便利な方法でそれらを分割する方法があります。イベントはJavaアプリケーションを介してキャプチャされ、Javaアプリケーションはイベントを検証してから、イベントテーブルに格納します。各イベントにはなりますuuid
し、recordtime
それが捕獲されたとき。
さらに、外部アプリケーションへのサブスクリプションが存在する可能性があり、カスタム基準に一致するすべてのイベントを取得する必要があります。新しい一致するイベントがキャプチャされると、そのイベントはサブスクライバーにプッシュされる必要があります。サブスクライバーがイベントを見逃さないようにするために、現在、キャプチャプロセスをシングルスレッドにするように強制しています。新しいイベントが発生すると、ロックが設定され、イベントはrecordtime
現在の時刻に割り当てられ、イベントは最終的にDBテーブルに挿入されます(明示的にコミットを待機します)。その後、ロックが解除されます。たとえば5秒ごとにスケジュールされて実行されるサブスクリプションのrecordtime
場合、最後に送信されたイベントを追跡し、などの新しいイベントのクエリを実行しますwhere recordtime > subscription_recordtime
。一致するイベントがサブスクライバーに正常にプッシュsubscription_recordtime
されると、はイベントmaxに設定されますrecordtime
。
すべてが実際に機能していますが、ご想像のとおり、シングルスレッドのキャプチャプロセスはあまり拡張性がありません。したがって、主な質問は次のとおりです。これを最適化して、たとえば複数のキャプチャプロセスを並行して実行できるようにするにはどうすればよいですか。
recordtime
挿入時にDB自体にを設定することはすでに考えていましたが、コミットの順序が保証されない(JVMが一時停止する)ため、2つのキャプチャトランザクションがほぼ同時に実行されているとイベントが失われる可能性があると思います。DBが生成したタイムスタンプを正しく理解すると、実際のコミットの前に設定されます。こうしてとのトランザクションrecordtime
T2がすでにサブスクリプションのクエリに見えることができる、との別のトランザクションがrecordtime
T1(T1 < T2)、まだ進行中であるので、コミットされていません。recordtime
サブスクリプションのは次のように設定され、T2、トランザクション1からイベントが失われますので...
イベントがキャプチャ/コミットされた順序で表示されるように、DBレベルで順序を保証する方法はありますか?新しく表示されるすべてのイベントには、前のイベントよりも後のタイムスタンプが必要です(厳密に単調に増加します)。フルテーブルロックについては知っていますが、そうすると、以前と同じパフォーマンスペナルティが発生すると思います。
シングルスレッドライターを使用するようにDBを設定することは可能ですか?次に、各キャプチャプロセスは、別の書き込みTXが完了するのを待機しますが、DBレベルでは、単一のインスタンス/スレッド化されたキャプチャアプリケーションよりもはるかに優れています。または、現在の状態を追跡するために別のフィールド/ IDを使用できますか?通常のシーケンスIDにも同じ理由があります。
イベントがキャプチャ/コミットされた順序で表示されるように、DBレベルで順序を保証する方法はありますか?
イベントのグローバルな順序について心配する必要はありません。イベントにはVersionプロパティが含まれている必要があります。イベントを作成するときは、特定のアグリゲート/ストリームIDに対して常に単調に増加するバージョン番号を挿入する必要があります。挿入するときに重要な順序は、これだけです。得意先ABCの場合、イベント1、2、3、および4では、イベント5のみを書き込む必要があります。
データベーストランザクションは、上記のルールを使用して、ストリーム内で正しい順序を保証できます。
たとえば5秒ごとにスケジュールされて実行されるサブスクリプションの場合、最後に送信されたイベントのレコード時間を追跡し、recordtime> subscription_recordtimeのような新しいイベントのクエリを実行します。
イベントを読むことは少し異なる話です。まず、イベントを一意に識別するためのシリアル列がある可能性があります。それはあなたに注文を与え、あなたがすべてのイベントを読んだかどうかを決定することを可能にします。ストアからイベントを読み取るときに、シーケンスのギャップを検出した場合。これは、最新のイベントを読んだときに挿入物が飛行中であった場合に発生します。この場合、データを再度読み取り、ギャップがなくなったかどうかを確認します。これには、サブスクリプションがインデックス内での位置を維持する必要があります。代替的または追加的に、少なくともNミリ秒前のイベントを読み取ることができます。ここで、Nは、トランザクションの遅延(500または1000など)を補正するのに十分な高さのしきい値です。
また、プロセスで使用または活用できるオープンソースのRDBMSイベントストアがあることにも注意してください。
マーテン:http://jasperfx.github.io/marten/documentation/events/
SqlStreamStore:https://github.com/SQLStreamStore/SQLStreamStore
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加