「イベント駆動」とはどういう意味ですか?
2017年2月7日
昨年末、私はThoughtworksの同僚と「イベント駆動型」アプリケーションの本質について議論するワークショップに参加しました。ここ数年、私たちはイベントを多用するシステムを多数構築してきましたが、それらはしばしば賞賛され、しばしば非難されてきました。北米オフィスがサミットを主催し、世界中のThoughtworksのシニア開発者が集まってアイデアを共有しました。
サミットの最大の成果は、人々が「イベント」について語るとき、実際にはかなり異なる意味を指していることを認識したことでした。そこで、私たちは有用なパターンとは何かを解き明かすために多くの時間を費やしました。このメモは、私たちが特定した主なパターンを簡単にまとめたものです。
イベント通知
これは、システムがドメインの変更を他のシステムに通知するためにイベントメッセージを送信するときに発生します。イベント通知の重要な要素は、ソースシステムが応答をあまり気にしていないということです。多くの場合、応答はまったく期待されておらず、応答がある場合でも、ソースが気にするのは間接的なものです。イベントを送信するロジックフローと、そのイベントへの何らかの反応に応答するロジックフローの間には、明確な分離があります。
イベント通知は、結合度が低く、セットアップが非常に簡単であるため優れています。ただし、さまざまなイベント通知にわたって実行されるロジックフローが実際にある場合は問題になる可能性があります。問題は、そのようなフローがプログラムテキストで明示的ではないため、確認するのが難しい可能性があるということです。多くの場合、このフローを把握する唯一の方法は、ライブシステムを監視することです。これにより、そのようなフローのデバッグと変更が難しくなる可能性があります。危険なのは、イベント通知を使用して適切に分離されたシステムを簡単に作成できることですが、大規模なフローを見失い、将来的にトラブルが発生する可能性に気付いていないということです。パターンは依然として非常に便利ですが、罠にはまらないように注意する必要があります。
この罠の簡単な例は、イベントが受動的攻撃的なコマンドとして使用される場合です。これは、ソースシステムが受信者にアクションを実行することを期待し、その意図を示すためにコマンドメッセージを使用する必要がある場合に発生しますが、メッセージを代わりにイベントとしてスタイル設定します。
イベントは多くのデータを運ぶ必要はなく、多くの場合、いくつかのID情報と、詳細情報を照会できる送信元へのリンクのみを運びます。受信者は何かが変更されたことを知り、変更の性質に関する最小限の情報を取得する可能性がありますが、次に何をすべきかを決定するために送信元にリクエストを返します。
イベント搬送型状態転送
このパターンは、システムのクライアントが、さらに作業を行うためにソースシステムに連絡する必要がないように更新する場合に表示されます。顧客管理システムは、顧客が詳細(住所など)を変更するたびに、変更されたデータの詳細を含むイベントを発行する場合があります。これにより、受信者は顧客データの独自のコピーを更新できるため、将来的に作業を行うためにメインの顧客システムと通信する必要がなくなります。
このパターンの明らかな欠点は、多くのデータがやり取りされ、多くのコピーが作成されることです。しかし、それは豊富なストレージの時代ではそれほど問題ではありません。私たちが得るものは、回復力の向上です。顧客システムが利用できなくなった場合でも、受信システムは機能できるためです。顧客情報にアクセスするためにリモートコールが必要ないため、レイテンシが短縮されます。すべてのコンシューマーシステムからのクエリを満たすために、顧客システムの負荷を心配する必要はありません。しかし、必要なときに送信者に詳細を要求する方が通常は簡単であるため、すべての状態の維持を整理する必要があるため、受信者側でより複雑になります。
イベントソーシング
イベントソーシングのコアアイデアは、システムの状態を変更するたびに、その状態の変更をイベントとして記録し、将来いつでもイベントを再処理することにより、システムの状態を確実に再構築できるということです。イベントストアが真実の主要なソースになり、システムの状態は純粋にそこから派生します。プログラマーにとって、この最適な例はバージョン管理システムです。すべてのコミットのログがイベントストアであり、ソースツリーの作業コピーがシステムの状態です。
イベントソーシングには多くの問題が導入されますが、ここでは詳しく説明しませんが、いくつかの一般的な誤解を強調したいと思います。イベント処理が非同期である必要はありません。ローカルgitリポジトリを更新する場合を考えてみてください。これは、サブバージョンなどの集中型バージョン管理システムを更新する場合と同様に、完全に同期的な操作です。確かに、これらのコミットをすべて持つことで、あらゆる種類の興味深い動作を実行できます。gitはその良い例ですが、コアコミットは基本的に単純なアクションです。
もう1つのよくある間違いは、イベントソースシステムを使用するすべての人が、役立つデータを決定するためにイベントログを理解してアクセスする必要があると思い込むことです。しかし、イベントログに関する知識は限定される可能性があります。私はこれをソースツリー内のすべてのコミットを知らないエディターで書いています。それはディスク上にファイルがあると想定しているだけです。イベントソースシステムの処理の多くは、便利な作業コピーに基づいている可能性があります。イベントログ内の情報を本当に必要とする要素のみが、それを操作する必要があります。必要に応じて、異なるスキーマを持つ複数の作業コピーを持つことができます。ただし、通常、ドメイン処理とイベントログから作業コピーを派生させる処理の間には明確な分離が必要です。
イベントログを操作する場合、作業コピーが必要になるたびに最初からすべてのイベントを処理する必要がないように、作業コピーのスナップショットを作成すると便利なことがよくあります。実際、ここには二重性があります。イベントログを、変更のリストまたは状態のリストとして見ることができます。一方から他方を導き出すことができます。バージョン管理システムは、最高のパフォーマンスを得るために、イベントログでスナップショットと差分を混合することがよくあります。[1]
イベントソーシングには多くの興味深い利点があり、バージョン管理システムの価値を考えると簡単に思い浮かびます。イベントログは、強力な監査機能を提供します(会計トランザクションは、口座残高のイベントソースです)。イベントログをある時点まで再生することで、履歴状態を再作成できます。再生時に仮想イベントを挿入することで、代替履歴を調査できます。イベントソーシングにより、メモリイメージのような耐久性のない作業コピーを持つことが妥当になります。
イベントソーシングには問題もあります。結果が外部システムとの相互作用に依存する場合、イベントの再生が問題になります。時間の経過に伴うイベントのスキーマの変更に対処する方法を理解する必要があります。多くの人は、イベント処理によってアプリケーションに多くの複雑さが加わると考えています(ただし、作業コピーを派生させるコンポーネントとドメイン処理を行うコンポーネント間の分離が不十分であるためではないかと思っています)。
CQRS
コマンドクエリ責務分離(CQRS)とは、情報の読み取りと書き込みに別々のデータ構造を持つという概念です。厳密に言えば、CQRSは設計にイベントが存在しない場合でもCQRSを使用できるため、イベントに関するものではありません。しかし、一般的に、人々はここで以前のパターンとCQRSを組み合わせるため、サミットでそれらが登場しました。
CQRSの正当性は、複雑なドメインでは、読み取りと書き込みの両方を処理する単一のモデルが複雑になりすぎるため、モデルを分離することで単純化できるということです。これは、多くの読み取りと非常に少ない書き込みなど、アクセスパターンに違いがある場合に特に魅力的です。ただし、CQRSを使用するメリットは、別のモデルを持つことの複雑さとバランスをとる必要があります。同僚の多くはCQRSの使用に深く警戒しており、誤用されることが多いと考えています。
これらのパターンを理解する
サンプルを収集することに熱心な一種のソフトウェア植物学者として、私はこれがトリッキーな領域であると感じています。根本的な問題は、異なるパターンを混同していることです。あるプロジェクトで、有能で経験豊富なプロジェクトマネージャーが、イベントソーシングは災害だったと私に語りました。変更を加えるには、読み取りモデルと書き込みモデルの両方を更新するために2倍の作業が必要でした。そのフレーズだけで、イベントソーシングとCQRSの間の潜在的な混同を検出できます。では、どちらが犯人であるかをどのように判断すればよいでしょうか?プロジェクトの技術責任者は、主な問題は多くの非同期通信であり、確かに既知の複雑さのブースターであるが、イベントソーシングやCQRSに必ずしも必要なものではないと主張しました。さらに、これらのパターンはすべて適切な場所では優れており、間違った場所に配置すると悪いことに注意する必要があります。しかし、パターンを混同していると、適切な地形がどのようなものかを理解するのは困難です。
この混乱をすべて解決し、各パターンをうまく実行する方法と、いつ使用すべきかについて確実なガイドラインを示す決定的な論文を書きたいと思っています。残念ながら、それを行う時間がありません。これが役立つことを願ってこのメモを書いていますが、本当に必要なものにはほど遠いことに気づいています。
参考資料
このトピックについて、goto Chicago 2017での基調講演で講演しました。
2006年に、私はP of EAA書籍の続編を作成することを考え、いくつかのプロトパターンを作成しました。残念ながら、10年経った今でも、この作業を続ける時間がありませんでした。ただし、当時私が書いたものは読むことができます。イベントについては、当時私がイベントの使用に関する考えをまとめたイベントに焦点を当てるから始めるのが良いでしょう。しばらく前のことですが、当時書いたことのほとんどは今でも有効だと思います。
これらの記事の中で最も影響力があるのは、イベントソーシングに関する記事です。これは主に、履歴状態と代替状態を形成するために再生を使用することの価値について述べています。
「イベントコラボレーション」の記事では、イベント通知とイベントキャリー状態転送のパターンに触れていますが、これらのパターンを混同しています(ワークショップ中に、これらが別個のものだと考え始めたのです)。
私は「CQRS」に関するブログ記事を書いています。
これらのトピックについては、ウェブ上にさらに多くの資料がありますので、楽しんで調べてみてください。私はそれらについて調べたり、推奨事項をいくつか選び出したりする時間を取っていないため、ここでは何もコメントはありません。
脚注
1: gitが.git/objects
にファイルやツリーの状態を保存しているため、イベントソーシングの例ではないと言う人が時々いますが、システムが内部ストレージに変化を使用するかスナップショットを使用するかは、イベントソーシングであるかどうかに影響しません。gitは必要に応じて、変更のリストを喜んで呼び出してくれます。また、データをパックファイルに圧縮する際には、パフォーマンス上の理由から選択されたスナップショットと変更の組み合わせを使用します。
更新
2017-02-08:イベントログとアプリケーション状態の使用に関する議論を調整し、gitとスナップショットの役割を明確にするための脚注を追加しました。