イベントソーシングに保存するべきイベントとは?
イベントソーシング開発に関して
株式会社ジェイテックジャパン CTOの高丘 @tomohisaです。ブログは久しぶりになります。昨年ジェイテックジャパンで色々ビジネスアプリケーションのアーキテクチャについて考慮した結果、イベントソーシングに可能性を感じて、社内で使えるイベントソーシングフレームワークを開発してきました。すでに既存システムの一部の機能に使われたり、新規システムの開発にも使用中です。今年前半にできればオープンソース化をしたいと考えていて、現在準備中です。
今回のプロジェクトで選択したプログラミング言語はC#です。また、データストアにはCosmosDBを利用しています。C#を採用した主な理由は、現在社内の多くのプロジェクトでC#を使っているため、社内メンバーが使いやすいという理由です。C#は、イベントソーシングの多くのサンプルが用意されており、開発をスムーズに開始できました。C#は関数型言語ではありませんが、関数型のスタイルや宣言型のスタイルを可能な限り取り入れることのできる機能が豊富に備わっています。
データストアに関しては、ジェイテックジャパンでは主にAzureを利用しており、そのためCosmosDBを選択しました。基本的には、パーティション機能があるドキュメントデータベースであれば、イベントソーシングの構築に対して問題がないと考えています。将来的には、PostgreSQLやDynamoDBにも対応することを計画しています。
イベントソーシング向きのイベントとは
イベントソーシングを利用することで、システムを構築する際に「イベント」を使って集約を形成できます。
さらに、集約ごとにあるいは全てのイベントを取得して、現在のステータスを構築する「プロジェクション」という作業があります。これは映像を投影するのと同じようなもので、最初のイベントから順番に集約を更新することで、現在の集約の状態を知ることができます。
各イベントによってステータスが変化することを表現する場合には、イベントソーシングは非常に有効です。
しかし、全てのデータがイベントソーシングに向いているわけではありません。
イベントソーシングにあまり向いていなかった「ログ的」なイベント
1つの事例として、社内でイベントソーシングを使用して作成した「動作ログの記録」という機能があります。これはログの数が多いもので、1日あたり1つのインスタンスにつき500から1000のイベントが記録されることもあります。保存するにあたり、ドキュメントDBに十分に保存できる量なので、保存には問題はありません。
ただ、このイベントを「イベントソーシング」のためのイベントとして保存してみたときに、以下の点に気が付きました。
- イベントは記録されているが集約の動作は変わらない
- イベントの使い方としては、気になる日時のイベントの一覧を取得して一覧で確認することが目的
- 「プロジェクション」は、イベントの一覧の配列を作成するために使用する
- イベントの種類によってビジネスロジックが変わるようなことはない
このような状況では、イベントソーシングを使う必要はありません。プロジェクションはCPU、メモリのリソースをかなり消費します。シンプルなログ作成のためだけにそれだけのリソースを使用する意味はありません。シンプルなログのリストを作成するだけなら、単にログをデータとしてDocumentDBに保存して、ログのリストを取得する機能を作るほうが良いと感じています。
イベントソーシングに向いているイベント種類とは
では、イベントソーシングに向いているイベントとはどんなものでしょうか。最近リリースされたCodeOpinionというYouTubeチャンネルの以下のビデオでも説明されていました。(英語ですが)
このビデオでは、イベントドリブンアーキテクチャの実践において重要なのが、異なるタイプのイベントを正しく使い分けることであると説明されています。「イベントソーシング」に使用すべきイベントに関しては、「"Events as State" : ステートとしてのイベント」と言われています。これは、イベントによって状態が変化し、その変化をビジネスロジックで活用する場合に適しているということを意味しています。
また、イベントソーシングおよびCQRSに関して2000年代から多くの講演をしているGreg Young(グレッグ・ヤング)の言葉を引用しています。
ちょうど今Greg Youngはついにイベントソーシングに関する本を書いているようです。ここ数ヶ月Greg Youngは多くの執筆中の文章やコンセプトについてTwitterでオープンに語っているので、みていて興味深いです。執筆もかなり佳境に来ているようなので、本がリリースされるのを楽しみにしています。
上記のツイートでイベントソーシングとはということに関して以下のように書いています。
Event Sourcing is that we will store facts witch have occurred.
Any state that we have is derived off of this set of facts.
Any state that we have is transient.
This is Event Sourcing "at it's core. We can discuss at length the many different ways
of achieving these properties but this is event sourcing."
簡単に訳すと以下のようなものです。
イベントソーシングは発生した事実を保存すること。
全ての状態(ステート)はこの事実の集合から導き出すことができる。
そして全てのイベントは一過性のものです。
これかイベントソーシングの核心でイベントソーシングに関する多くの話はこれをどのように実現するかについて語っています
確かにここに書いている通り、イベントによりステートを変えることがイベントソーシングの核心であるとのことです。ステートが変わることにより、そこにロジックを組み入れることができるようになり、それによりビジネス上の問題を解決できるということです。
最初の疑問、「イベントソーシングに向いているイベント種類」に関しては以下の答えとなります。
- 「特定の集約のステートを変化させる事実を記録したイベント」に向いている
- 「ログ的」なイベントはイベントソーシングで使えるが、向いていない
イベントソーシング用のイベント以外にどのようなイベントがあるか
上記のCodeOpionの動画では、イベントソーシング用のイベントと、その他のイベントの使用用途をざっくりと以下の理由に分けています。
- イベントソーシング用のイベント:ステート管理のため
- その他のイベント:コミュニケーションのため
コミュニケーションのためのイベントのために、Kafkaなどのメッセージブローカーを使うわけですね。これがわかると、イベントソーシングのために必ずしもメッセージブローカーサービスを使わなくて良いことがわかります。
コミニケーションのためのイベントの種類には以下のものなどがあります。
- サービス間の同期を取るためのイベント
- データの変化を更新するためのイベント
- 通知をしてイベントドリブンで他の機能を呼び出すためのイベント(メール送信など)
- 統合イベント(ワークフローを実行するためのイベント)
インテグレーションイベント(統合イベント)とイベントソーシング用のイベントの内容は似ています。違いは、集約内のステートの変化を表すのがイベントソーシング用のイベントで、集約外に影響を及ぼすものが、インテグレーションイベント(統合イベント)とのことです。
これらの多くのイベント種類ははっきり切り分けられるわけでなく、1つのイベントを複数の用途のためにも使用できます。そのため混乱しやすいのですが、イベントの目的をはっきり理解すれば、イベントドリブンアーキテクチャでどの部分にどの技術を使用するかを切り分けやすくなります。
まとめ、イベントソーシング用のイベント、ドキュメントDBに保存するデータ、RDBに保存するデータのバランス
このように考えていくと、イベントソーシング用のデータ、ドキュメントDBに入れるデータ、RDBに入れるデータの方向性が見えてきました。
- イベントソーシング : ビジネスロジックに影響する事実、変化を表現するイベント、ドメイン知識に影響するデータ
- ドキュメントDB : データ量が多いもの、書き込み回数が多いもの、ユーザーから送信されたデータ
- RDB :(複雑な)クエリが必要なもの、検索結果が早めに欲しいデータ、マテリアライズドビュー用途
などのデータなど、それぞれに向き不向きのデータがあります。その点について、社内の他のエンジニアと話したのですが、まとめた図が以下のものになります。
イベントソーシングについて使ってみて利点や向いていない部分も少しずつわかってきました。イベントソーシングの機能は強力で、これから私たちがアプリケーションのステートの保存に関して多くの場合で選択するソリューションとなりそうです。これからも少しづつイベントソーシシングの色々なテーマに関して記事を書いていきたいと考えています。
追記 2/14 この記事の反応からアイデアを得て以下の記事を書きました
Discussion