web-dev-qa-db-ja.com

最高のイベントソーシングdb戦略

小さなイベントソースライブラリをセットアップしたい。オンラインでいくつかのチュートリアルを読みましたが、これまでのところすべてが理解されています。

唯一の問題は、これらのさまざまなチュートリアルには2つの異なるデータベース戦略がありますが、使用するものを使用する理由はコメントなしです。

それで、私はあなたの意見を聞きたいです。そして重要なのは、なぜあなたが選んだソリューションを好むのかということです。

  1. ソリューションは、イベントごとに1つのテーブルを作成するdb構造です。

  2. 解決策は、汎用テーブルを1つだけ作成し、イベントをシリアル化された文字列として1つの列に保存するdb構造です。

どちらの場合も、イベントの変更をどのように処理するかはわかりませんが、まったく新しいものを作成する可能性があります。

敬具

27
SharpNoiZy

Libをソースする独自のイベントを作成し、オプション2を選択しました。その理由は次のとおりです。

  • イベントタイプではなく集約IDによってイベントストリームをクエリします。
  • それらがすべて異なるテーブルにある場合、イベントを順番に再現するのは苦痛です
  • イベントのアップグレードが少し苦痛になります

集約ごとにイベントを保存できるという主張がありますが、それはプロジェクトの要件によって異なります。

役立つと思われるイベントストリームの使用方法についての投稿がいくつかあります。

34
Codescribler

解決策は、汎用テーブルを1つだけ作成し、イベントをシリアル化された文字列として1つの列に保存するdb構造です

これは、イベントの再生がより簡単であるため、最善のアプローチです。イベントソースに関する私の2セント:これは素晴らしいパターンですが、すべてが見た目ほど単純ではないため、注意が必要です。私が取り組んでいたシステムでは、集約ごとにイベントのストリームを保存しましたが、オブジェクトの最新の状態を取得するためにすべてのイベントを実行する必要があることを受け入れることができなかったため、まだ正規化されたテーブルのセットがありました(スナップショットは役立ちますが、完璧なソリューションではありません)。はい、イベントソースは細かいパターンです。エンティティの完全なバージョン管理と完全な監査ログを提供し、正規化されたテーブルのセットの代わりとしてではなく、そのためにのみ使用する必要がありますが、これは私の2つだけですセント。

13
MeTitus

最善の解決策は、#2を使用することだと思います。また、mysqlのようなトランザクションデータベースを使用すると、現在の状態を関連するイベントと同時に保存できます。

私は本当に解決策を好きではないし、推奨しません#1

#1に対する懸念がイベントのバージョン管理/アップグレードに関するものである場合;次に、新しい変更ごとに新しいクラスを宣言します。怠けすぎないでください。または再利用に取りつかれます。サブスクライバーに変更について知らせます。イベントバージョンを提供します。

#1に対する懸念がイベントのクエリ/解釈のようなものである場合;その後、イベントをいつでも簡単に(元のデータベースから)nosqldbまたはイベントストアにプッシュできます。

また;私がイベントソーシングライブラリに使用するパターンは次のようなものです:

public interface IUserCreated : IEventModel
{

}

public class UserCreatedV1 : IUserCreated
{
    public string Email { get; set; }
    public string Password { get; set; }
}

public class UserCreatedV2 : IUserCreated
{
    // Fullname added to user creation. Wrt issue: OA-143

    public string Email { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class EventRecord<T> where T : IEventModel
{
    public string SessionId { get; set; } // Can be set in emitter.
    public string RequestId { get; set; } // Can be set in emitter.
    public DateTime CreatedDate { get; set; } // Can be set in emitter.
    public string EventName { get; set; } // Extract from class or interface name.
    public string EventVersion { get; set; } // Extract from class name
    public T EventModel { get; set; } // Can be set in emitter.
}

public interface IEventModel { }

そう;イベントのバージョン管理とアップグレードを明示的に行います。ドメインとコードベースの両方で。新しいイベントのオリジンを展開する前に、サブスクライバーで新しいイベントの処理を実装します。そして;必要でない場合、外部サブスクライバーからのドメインイベントの直接消費を許可しないでください。統合層などを配置します。

私の考えがあなたに役立つことを願っています。

4
Safak Ulusoy

私は、次のもので構成されるイベントソーシングアプローチについて読みました。

  1. 集計とイベントの2つのテーブルがあります。
  2. 次のいずれかのユースケースに基づいてください:

    a。 ID、バージョン= 0およびイベントタイプを生成し、イベントテーブルにイベントを作成し、集計テーブルにレジストリを作成します。

    b。 IDまたはイベントタイプごとに集計テーブルからイベントを取得し、ビジネスケースを適用してから集計テーブル(バージョンとイベントタイプ)を更新し、イベントテーブルにイベントを作成します。

このアプローチでは集計テーブルの一部のフィールドを更新しますが、集計テーブルに集計の最新バージョンがあるため、イベントテーブルを追加のみとして残し、パフォーマンスを向上させます。

2
Felipe

#2に進みます。イベントタイプを介した効率的な検索方法が必要な場合は、その列にインデックスを追加します。

0
Jacob Zimmerman

このケースに関係するサブジェクトに関するデータにアクセスするための2つの戦略を次に示します。 1)現在の状態と2)イベントの順序付け。現在の状態では、イベントを処理しますが、サブジェクトの最後の状態のみを保持します。イベントシーケンスでは、状態が必要になるたびにイベントを処理することにより、イベントを保持し、現在の状態を再構築します。イベントシーケンスは、現在の状態の原因となったすべてを追跡できるため信頼性が高くなりますが、効率的ではありません。すべてのイベントを常に再処理しないように、最後の状態だけでなく中間状態(スナップショット)も保持するのが常識です。これで、信頼性とパフォーマンスが向上しました。

暗号通貨には、イベントシーケンスとローカルスナップショットがあります。名前のローカルは、ブロックチェーンが配布され、データが複製されるためです。

0
user3783189