5

私が見たグレッグ・ヤングにインスパイアされたさまざまな例に沿った実践と原則を使用して、イベントソーシングシステムを実装しようとしています。

バージョン チェック ロジックのしくみと、集計を保存するときに、現在のバージョンが予想されるバージョンと一致しない場合は、別のセッション/クライアント アプリが集計を更新する前に更新したことを意味することを理解しています。

また、同時イベントが保存されたときに競合をさかのぼって解決する方法を用意できることも理解しています。この質問は、これを行うことではありません。

私が理解しようとしているのは、ravendb などの nosql データベースをイベント ストアとして使用する特定の実装では、競合状態のために書き込まれたイベントがバージョン番号と重複しないようにするにはどうすればよいかということです。

サンプル プロジェクトからの次のコードを示します。

Repository<TAggregate>リポジトリ クラスには save メソッドがあります

    public void Save(AggregateRoot aggregate, int expectedVersion)
    {
        if (aggregate.GetUncommittedChanges().Any())
        {
            lock (_lockStorage)
            {
                var item = new T();

                if (expectedVersion != -1)
                {
//issue if two processes get to this line of code below together 
//and both have the same 'version to be expected' then start writing together
                    item = GetById(aggregate.Id); 
                    if (item.Version != expectedVersion)
                    {
                        throw new ConcurrencyException(string.Format("Aggregate {0} has been previously modified",
                                                                     item.Id));
                    }
                }

                _storage.Save(aggregate);
            }
        }
    }

基本的に、アプリケーションが 1 つしかない場合、これは問題なく機能します。ロックは、現在のスレッドがロックを取得し、バージョンをチェックしてから、独自のイベントを書き込んでいる間、他のスレッドがイベント ストアにイベントを書き込んでいるのを停止します。

ただし、異なるマシンで実行されている 2 つの別個のクライアントを想像してみてください。明らかに、2 つのプロセスは両方とも一緒にロックされ、GetById()メソッドを実行して、現在コミットされている同じバージョンを確認できます。両方のプロセスは、バージョン番号をインクリメントして、コミットされていないイベントを書き込みます。ただし、これにより、アグリゲートのイベント ストリームは、同じバージョン番号の異なるイベントが存在する可能性がある状態のままになります。

ある種のレトロスペクティブな解決策を実行できることは知っていますが、それは私が達成しようとしていることではありません。

これは明らかに、イベント ストア データベース側で何らかのロックを行う必要があることを意味します。誰でもこれを行う方法をアドバイスできますか? 回答はデータベース固有である必要はありませんが、イベント ソーシング システムのプロトタイプを作成しようと計画しているため、ravendb の例は素晴らしいでしょう。

4

2 に答える 2

1

異なるマシンで実行されている 2 つの別々のクライアントが API を介してアプリケーションと対話できない理由はありますか? そうすれば、イベントの中央処理が1台のマシンで処理され、説明した問題を回避できます。部分的に接続されたシナリオを参照している場合でも、クライアントでこのロジックを実行することはありません。やむを得ない場合は、ある時点でイベント ストリームを結合してから競合を処理する必要があります。

同時実行の問題の処理に関する投稿が役立つ場合は、正確なシナリオを処理するわけではありませんが、同時実行の競合解決に関するアイデアが得られる場合があります。

于 2014-11-18T15:35:44.687 に答える
1

基になるデータベースが既にこれをサポートしている場合は、楽観的同時実行制御を自分で実装しないでください。

通常、これは、データがあると予想されるバージョンをデータベース サーバーに渡すことによって実装されます。バージョンが現在のバージョンと一致する場合にのみ、更新が正常に行われます。

RavenDB は、楽観的同時実行制御に e タグを使用します。

于 2015-03-21T17:18:26.243 に答える