イベントの調達、再生、バージョン管理


8

イベントソーシング、CQRS、マイクロサービスを使用するシステムを設計しています。これは珍しいパターンではないことを理解しました。このサービスの重要な機能は、記録システムから再水和/復元する機能である必要があります。マイクロサービスは、MQ(Kafka)でコマンドとクエリを生成します。他のマイクロサービスが応答します(イベント)。コマンドとクエリは、監査と復元の目的でS3に保持されます。

現在の思考プロセスは、システムを復元するために、S3からイベントログを抽出し、単純にKafkaにフィードバックできるというものでした。

しかし、これは時間の経過に伴う生産者消費者の両方の変化を認めることができません。コマンド/クエリレベルでのバージョン管理は、問題の解決にある程度役立つようですが、復元中のコマンドが受信および処理されたときに、まったく同じになるようにコンシューマーのバージョン管理を行うことはできません。 [のバージョン]コマンドを最初に受信したときに処理を実行しているコード。

これを解決するために使用できるパターンはありますか?この機能を宣伝する他のシステムを知っている人はいますか?

編集:例を追加します。

「バイヤー」が私のオークションサイトの「セラー」に「質問」を送信します。フローは次のようになります。 UI -> Web App: POST /question {:text text :to seller-id :from user-id} Web App -> MQ: SEND {:command send-question :args [text seller-id user-id]} MQ -< Audit: <command + args appended to log in S3> MQ -< Questions service: - Record question in DB - Email seller 'You have a question'

新しいビジネス要件の結果として、私は「質問サービス」コンシューマーを調整して、すべての未読の質問の数を保持します。DBスキーマが変更されます。これまで、売り手が質問を読んだかどうかはわかりませんでした。最後の行は次のようになります:

MQ -< Questions service: - Record question in DB - Email seller 'You have a question' - Increment 'unread questions count'

変更前と変更後の2つのコマンドが問題です。「未読の質問数」は1です。

システムがクラッシュします。新しいコードを使用してコマンドを再生することにより、復元しました。復元の最後では、「未読の質問数」は2になります。この不自然な例では、結果は大惨事ではありませんが、復元された状態は以前の状態ではありません


問題はいくつかの懸念を混ぜ合わせているようです。イベントソーシングは、基盤となるデータに多くの変更が加えられているシステムに対処するためのアーキテクチャ戦略です。DTOおよびバックアップとデータのバージョン管理は、まったく別の問題です。イベントソーシングは、ベアメタル復元機能を実現するように特別に設計されたものではありません。そのためには、特定の戦略を用意する必要があります。
theMayer 2016

多分イベントアップキャストはあなたの問題を解決することができます:blog.trifork.com/2012/04/17/...
ソンゴ

@ rmayer06私は例が私が求めているものだと思います!
アントニーウッズ

回答:


16

まず、コマンドイベントの違いを理解して活用できるようにすることが重要です。

この質問は簡潔に指摘し、コマンドは、我々が起こるしたいものです、そしてイベントは、すでに起こっているものです。コマンドは、必ずしもシステムで重要なイベントを発生させるわけではありませんが、通常は発生します。たとえば、send messageコマンドが拒否される場合があります。その場合、イベントは発生しません(診断ログに記録することを選択することもできますが、通常、この意味でエラーはイベントとは見なされません)。これで、send messageコマンドが受け入れられるとmessage sentイベントが発生し、イベントの詳細で送信者、受信者、およびコンテンツを説明できます。

システム状態について話すとき、実際にはコマンドの集まりではなく、イベントの集まりについて話し合っています。 システムの状態を変化させることができるのはイベントだけです。生活の例から引き出すために、私が地元のPublixスーパーマーケットに行って、フロリダの宝くじを購入するとします。コマンドは「チケットの購入」、イベントは「チケット発行」でした。私の次のコマンドは、パワーボールの私の数字を抽選することです。宝くじは私の命令を無視します(しかし、私には知識がありません)。そして、「PowerBall番号が選択されました」というイベントは私の希望に関係なく行われます。私の番号が一致する場合、「ジャックポットが勝った」というイベントが私に起こります(そして、私の命令が聞こえたと思います)。そうでない場合は、コマンドが無視されたことに気づきました。

歴史的な観点から見ると、宝くじはイベントのサブセットにのみ関心があります。宝くじは、(a)チケットが発行されたこと、(b)番号が選択されたこと、および(c)ジャックポットが当たったことのみを気にします。それらは興味のあるアイテムです。チケットを購入したり、当選したいなどの行為は、関係ありません。負けた後のチケットの場合も同様です。ありふれたイベントでは現実の世界は変わりますが、システムにとって重要なイベントのみを記録する必要があります。

理論的には、イベントソーシングテクニックでは、イベントのストリームを最初から再生して現在の状態に到達させることができます。これは、根本的なシステム条件が一定で決定論的であるという仮定に依存しています。ただし、これらの仮定は多くのシステムで有効ではありません。イベントに関連するデータや、関心のあるイベントの種類は、コンピューターソフトウェアの進化に伴って変化する可能性があります。さらに、すべてのクエリに応じて現在の状態を再計算すると、計算コストが高くなる可能性があります。このため、システム状態のスナップショットは、既知の時点を表すために取られることが多く、最新のイベントを追加できます。

イベントストリームを複数のバージョンにまたがって再生することは依然として可能ですが、これを行うために必要な人間の労力は、コストが非常に高くなる可能性があります。システムにその機能を設計する正当な理由がない限り、スナップショットを利用するようにシステムを構築する方がよいでしょう。

問題の例

質問の例では、アーキテクチャは本当にイベントベースではありません。コマンドベースです。コマンドを再生すると、システム状態が作成されます。これはアンチパターンであり、修正する必要があります。代わりに、主なイベントは次のとおりです。

  • バイヤーが質問する
  • 販売者が質問に回答する

これらの各イベントを「再生」して、現在の状態を確認できます。たとえば、質問をする際のシステムの動作は、販売者に電子メールを送信してunanswered questionカウンターをインクリメントすることです。この動作は変更できます。しかし、質問が出されたという事実はそうではありません。同様unanswered questionに、売り手が応答すると、システムはカウンターをデクリメントします。この動作は変更可能ですが、売り手が応答したという事実は変わりません。

ほとんどのイベントソーシングシステムは、クエリに応答して特定のイベントストリームを再生することにより、未回答の質問の数を動的に計算します。


これは素晴らしい回答です。ありがとう@ rmayer06
Antony Woods

この宝くじの例では、「イベントのみがシステムの状態を変化させる可能性がある」と述べていますが、イベントが「チケット発行」である場合(そしておそらくイベントにタイムスタンプ、buyer_id、ticket_idなどの詳細が含まれている場合)、 IDを生成する他の記録システムがない場合は、チケットの参照番号を記録しますか?イベントソースが過去形として事実を記録する前に、最初にチケットを作成する必要がある従来のCRUDシステムはありますか?
ホーマン

チケットを発行する作用がある。この場合、イベント。イベントに関連付けられているデータは、質問でイベントとして説明されているものであり、有用ですが技術的には正しくありません。さらに、イベントは通常、細部のホラーチを表し、各方向で比較的無制限に構成および分解できます。
theMayer

ええと...あなたは私の恐ろしいことで私の心を吹き飛ばした。
Homan、2016年

私が考えていたのはこれだと思います。CRUDの世界、特にRailsでは、テーブルの主キーのIDが自動インクリメントされるのが一般的です。IDを知らずにレコードを作成すると、DBからチケットIDが返されます。私が読んだことから、イベントソーシングの世界に移動すると、イベントはDBに永続化される前に「実現」され、集約IDが必要になります。そのため、DBから永続化した後にIDを取得するのではなく、一意のIDがすでにわかっている必要があるため、全体として説明できます。これは、自動IDではなく常にUUIDを作成する必要があるようです。
Homan

3

コマンドとクエリは、監査と復元の目的でS3に保持されます。

監査については、確かに。以下のための復元?それは奇妙で、頭痛の種になるでしょう。

イベントソーシングを行う場合は、コマンドではなく、イベント(過去に発生したこと)から状態を復元する必要があります。これにより、コマンド実装の変更に関連する問題のほとんどを回避できます。永続的な状態変更に対処するだけで済みます。

バージョン管理はまだ問題です。特に、永続化されたイベントができるだけしなやかであることを確認する必要があります(ドメイン内の概念を直接シリアル化するのではなく、DTO表現)。ストアからイベントを読み取るとき、それらを再水和状態に適用する前に、必要に応じてイベントを更新する機会があります。


わかりましたので、コマンドからの復元ではなく、イベントからの復元について心配することをお勧めします。たとえば、「10個の豆を追加する」というコマンドを受け取った場合、「10個の豆が追加されました。新しい合計:40」というイベントを発行して保存する必要がありますか?
アントニーウッズ

はい、そうです。イベントソースエンティティの各状態変化は、1つ以上のイベントによって表されます。水分補給するには、すべてのイベントを順番に再生します。
VoiceOfUnreason 2016

2
この回答には同意しませんでしたが、理解を深める上で非常に重要でしたので、貢献に感謝します。私がrmayer06の回答を選んだのは、迅速な回答を得るためにこの質問にアクセスするだけの人にとって、より直接的で丸みがあり、より有用だったからです。
アントニーウッズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.