AxonFramework,EventStore実装

7764 ワード

イベント・トレーサビリティ・リポジトリには、イベント・ストレージ(event store)が集約からイベントを格納およびロードする必要があります.イベントストレージは、パブリッシュされたイベントを永続化し、集約識別子に基づいてイベントを取得できるイベントバスの機能を提供します.
Axonは、EmbeddedEventStoreというオープンボックスで使用できるイベントストレージを提供しています.イベントの実際のストレージとEventStorageEngineへの取得を依頼します.EventStorageEngineの実装は複数あります.

JpaEventStorageEngine


JpaEventStorageEngineは、JPA-compatibleデータソースにイベントを格納します.JPAイベントは、いわゆるエントリにイベントを格納する.これらのエントリには、イベントのシーケンス化形式が含まれ、領域メタデータを格納してエントリを迅速に検索します.JpaEventStorageEngineを使用するには、クラスパスにJPA注釈(javax.persistence)が必要です.
デフォルトでは、META-INF/persistence.xmlで定義されているように、イベントストレージには、DomainEventEntryとSnapshotEventEntry(両方ともorg.axonframework.eventsourcing.eventstore.jpaパッケージ)を含む永続化コンテキストを構成する必要があります.次に、永続化コンテキスト構成の構成例を示します.
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="eventStore" transaction-type="RESOURCE_LOCAL"> (1)
        <class>org...eventstore.jpa.DomainEventEntryclass> (2)
        <class>org...eventstore.jpa.SnapshotEventEntryclass>
    persistence-unit>
persistence>
  • この例では、イベントは特定の永続化ユニットを格納する.しかし、他の永続化ユニットの構成に3行目を追加することを選択することができます.
  • この明細は、JpaEventStoreで使用されるクラスのDomainEventEntryを永続化コンテキストに登録します.

  • Axonは、2つのスレッドが同じ集約にアクセスすることを防止するためにロックを使用することに注意してください.しかし、同じデータベースに複数のjvmがある場合は、これは役に立ちません.この場合、データベースに依存して競合を検出する必要があります.同時アクセス・イベント・ストレージは、テーブルが集約を許可するのに1つのシリアル番号しかないイベントのため、既存のシリアル番号で2番目のイベントを挿入するとエラーが発生するため、プライマリ・キー制約に違反します.JpaEventStorageEngineは、このエラーを検出してConcurrencyExceptionに変換できます.ただし、各データベース・システムは、この違反を異なる方法で報告します.JpaEventStoreでデータ・ソースを登録すると、データベースのタイプを検出し、エラー・コードがプライマリ・キー制約に違反していることがわかります(Key Constraint Violation).あるいは、指定された例外がプライマリ・キー制約違反(Key Constraint Violation)を表す場合、P e r s i stenceExceptionTranslatorインスタンスを提供することもできます.データ・ソースまたはP e r s i stenceExceptionTranslatorが提供されていない場合は、データベース・ドライバから例外がそのまま放出されます.
    デフォルトでは、JPAイベントストレージエンジンには、EventStorageEngineで使用されているEntityManagerインスタンスを返すEntityManagerProvider実装が必要です.これにより、アプリケーションが使用する永続化コンテキストを管理できます.EntityManagerProviderの責任は、適切なEntityManagerインスタンスを提供することです.
    いくつかのEntityManagerProviderの実装が利用可能で、それぞれ異なるニーズがあります.SimpleEntityManagerProviderは、構築時にのみEntityManagerインスタンスを返します.これにより、コンテナ管理コンテキストの簡単な選択が実現される.ContainerManagedEntityManagerProviderは、デフォルトの永続化コンテキストを返し、その使用デフォルトはJPAイベントによって格納されます.永続化ユニットが「myPersistenceUnit」と呼ばれている場合は、JpaEventStoreで使用したいと考えています.これがEntityManagerProvider実装で、次のように見えます.
    public class MyEntityManagerProvider implements EntityManagerProvider {
    
        private EntityManager entityManager;
    
        @Override
        public EntityManager getEntityManager() {
            return entityManager;
        }
    
        @PersistenceContext(unitName = "myPersistenceUnit")
        public void setEntityManager(EntityManager entityManager) {
            this.entityManager = entityManager;
        }

    デフォルトでは、JPAイベントストアは、DomainEventEntryエンティティとSnapshotEventEntryエンティティにエントリを格納します.多くの場合、これで十分ですが、これらのエンティティが提供するメタデータが不足している場合に遭遇する可能性があります.または、異なる集約タイプのイベントを異なるテーブルに格納したい場合があります.もしそうなら、JpaEventStorageEngineを拡張することができます.いくつかのprotectedメソッドが含まれており、その動作を調整するために書き換えることができます.
    警告Hibernateなどの永続化プロバイダは、EntityManagerインプリメンテーションで1レベルのキャッシュを使用することに注意してください.通常、これは、EntityManagerに属するすべてのエンティティがクエリーで使用または戻されることを意味します.これらは、周囲のトランザクションがコミットされた場合、またはトランザクションで明示的なパージが実行された場合にのみパージされます.特に、クエリがトランザクションコンテキストで実行される場合です.この問題を解決するには、非エンティティオブジェクトのみがクエリーされていることを確認します.JPAの「SELECT new SomeClass(parameters)FROM...」スタイルのクエリーを使って、この問題を解決することができます.または、一連のイベントを取得した後にEntityManagerを呼び出す.flush()とEntityManager.clear().それができなかった場合、大きなイベント・フローを切断するとOutOfMemoryExceptionsになる可能性があります.

    JDBC Event Storage Engine


    JDBCイベントストアエンジンは、JDBC接続を使用して、JDBC対応のデータストアにイベントを格納します.通常、これらはリレーショナル・データベースです.理論的には、いずれのJDBCドライバもJDBCイベントストレージエンジンをサポートするために使用することができる.
    JDBCイベントストアエンジンは、JPAと同様にイベントをエントリに格納する.デフォルトでは、各イベントはテーブルのローに対応する個別のエントリに格納されます.1つのテーブルはイベントに使用され、もう1つはスナップショットに使用されます.
    JdbcEventStorageEngineはConnectionProviderを使用して接続を取得します.通常、これらの接続は、データ・ソースから直接取得できます.しかし、Axonはこれらの接続を1つの作業ユニットにバインドし、1つの作業ユニットで1つの接続を使用します.これにより、同じスレッドに複数の作業ユニットがネストされていても、すべてのイベントを格納するために個別のトランザクションが使用されることが保証されます.
    Springユーザーは、SpringDataSourceConnectionProviderを使用して、データ・ソースから既存のトランザクションに接続することを推奨します.

    MongoDB Event Storage Engine


    MongoDBは、ドキュメントベースのNoSQLストレージです.伸縮性により、イベントストレージに適しています.AxonはMongoEventStorageEngineを提供し、MongoDBをデータベースサポートとして使用します.Axon Mongoモジュール(Maven artifactId axon-mongo)に含まれています.
    イベントは、2つの独立したセットに格納されます.1つは実際のイベントフロー、1つはスナップショットです.
    デフォルトでは、MongoEventStorageEngineは、それぞれのイベントをそれぞれのドキュメントに格納します.ただし、StorageStrategyの使用を変更する可能性があります.
    Axonが提供する選択肢は、DocumentPerCommitStoragesStrategyであり、すべてのイベントを個別のコミットに格納するために、個別のドキュメント(同じDomainEventStream)を作成します.
    1つの個別のドキュメントにコミット全体を格納する利点は、コミットが原子的に格納されることです.また、任意の数のイベントを1往復するだけです.欠点は、データベース内でイベントを直接クエリーすることがさらに難しくなることです.たとえば、レルムモデルを再構築する場合、「commit document」に含まれる場合、1つの集約「transfer」イベントから別の集約に移行することは困難です.
    MongoDBには多くの構成は必要ありません.必要なのは、ストレージ・イベントのセットへの参照だけで、開始できます.本番環境では、コレクション内のインデックスを二重にチェックしたい場合があります.

    Event Store Utilities


    Axonはいくつかのイベントストレージエンジンを提供しており、場合によっては役に立つ場合があります.
    SequenceEventStorageEngineは、他の2つのイベントストレージエンジンを囲むパッケージです.読み取り時には、この2つのイベントストレージエンジンからイベントが返されます.追加イベントは、2番目のイベントストレージエンジンにのみ追加されます.これは、パフォーマンス上の理由でイベントストレージを使用する2つの異なる実装の場合に有用であり、例えば.1つ目はより大きいが、より遅いイベントストレージであり、2つ目は最適化された高速読み取りと書き込みである.
    常駐メモリのストレージイベントEventStorageEngine実装:InMemoryEventStorageEngine.他のイベントストレージよりも優れている可能性がありますが、これは長期的な生産使用を意味しません.しかし、イベントストレージが必要なshort-livedツールやテストでは非常に役立ちます.

    Influencing the serialization process(シーケンス化プロセスに影響)


    イベントストレージには、ストレージにシーケンス化されたイベントを準備する方法が必要です.デフォルトでは、AxonはXStreamSerializerを使用し、XStreamを使用してXMLイベントにシーケンス化します.XStreamはかなり速く、Javaシーケンス化よりも柔軟です.また,XStreamシーケンス化の結果は人間が読むことができる.ログとデバッグに役立ちます.
    XStreamSerializerは構成できます.一部のパッケージ、クラス、フィールドに使用すべき別名を定義できます.潜在的な長い名前を短縮するほか、イベントのクラス定義の変更時に別名を使用することもできます.別名の詳細については、XStreamのWebサイトを参照してください.
    また、AxonはJacksonSerializerを提供し、Jacksonを使用してイベントをJSONにシーケンス化します.よりコンパクトなシーケンス化形式を生成すると、クラスはJacksonが要求する約束(または構成)を遵守する必要があります.
    注意Javaコード(または他のJVM言語)を使用してシーケンサを構成するのは簡単です.しかし,呼び出し方法の限界のため,Spring XMLプログラムコンテキストでは構成はそれほど簡単ではない.オプションの1つは、FactoryBeanを作成し、XStreamSerializerインスタンスを作成し、コードを構成することです.Springリファレンスの詳細を確認します.