CQRS + ESについてのまとめ
CQRS+ESというアーキテクチャがどういったものか気になったので調べたことをまとめてみた。
CQRSとは
コマンドクエリ責務分離(Command Query Responsibility Segregation)の略で、 データの読み込み(クエリ)と書き込み(コマンド)の責務を分離するアーキテクチャのこと。
コマンドモデル
- ユーザーインターフェースなどのクライアントから実行される振る舞いを持つ
- データの書き込みに責務を持つ
- 操作の成否以外の情報を呼び出し側に返さない
クエリモデル
- 非正規化したデータモデル
- データの表示のみに責務を持つ
- データモデルがSQLだった場合はクライアントの表示内容毎にテーブルを用意する
- 操作は冪等であることが保証される
クエリモデルの更新
コマンドモデルの実行時の最後にはイベントが発行される。
特別なサブスクライバが全てのイベントを受信していて、受け取ったイベントに沿ってクエリモデルを更新し、変更を反映する。
更新を同期的にするか非同期処理にするかはシステムの負荷がどれくらいかかるかによって選択されるべきである。
同期的な場合は一貫性が保たれるが、システム負荷は高くなる。
非同期処理の場合は負荷は抑えられるが、表示されるまでに時間がかかってしまう。
イベントソーシング(ES)とは
状態(State)を永続化するのではなく、Eventを永続化(ソーシング)すること。
ソフトウェアに何が起きたのか(Event)を記録しておくことで現在の状態を割り出す。
ステートソーシング
ステートソーシングとは通常のCRUDなアプリケーションでやっているようなもので、
最新の状態だけを永続化すること。
何故、どういう意図を持って状態が変更されたのかというような、状態が変更された経緯が見落とされる という問題がある。
イベントソーシングなら
- ソフトウェアの履歴が完全に保存される
- ある時点での状態を再現できる
状態遷移は,私たちの問題空間における重要部分であり,私たちのドメインでモデル化されるべきものです。
イベントソーシングの問題点
- 特定の名前のユーザをすべて検出するというようなクエリが,SQLデータベースで常にテーブルのフルスキャンを行わなければならないような非常に厄介なものになる可能性がある点
- 書き込みと読み込みを分離して、クエリを最適化することが可能な CQRS の出番
イベントソーシングで解決できる問題
- 商品の更新履歴
イベントを記録しておくことで在庫数を算出する
- 商品が在庫数10で出品された ⇢ 在庫10
- 商品が1個購入された ⇢ 在庫9
- 商品が1個購入された ⇢ 在庫8
- 出品者が商品の個数を10に変更した ⇢ 在庫10
例えば4のイベントを取り消したければ3のイベントまで再生することで状態を再現出来る。
イベントストア
イベントを永続化する為のデータストア。
CQRS考案者による実装
ActiveRecord ベースの実装
https://github.com/arkency/rails_event_store
CQRSとESの組み合わせ
クエリモデルとコマンドモデルをそれぞれ永続化すると、コマンド発行後にクエリモデルが同期されていることを担保することが難しい。
そこでイベントソーシングを組み合わせることで、コマンドモデルでイベントの永続化を行い、永続化されたイベントによって用途に合わせ何度でもいくらでも最適化されたクエリモデルを作ることが可能になる。
参考文献
http://postd.cc/using-cqrs-with-event-sourcing/
https://www.slideshare.net/shuheifujita90/ss-14294169
https://www.infoq.com/jp/news/2014/10/greg-young-event-sourcing
http://d.hatena.ne.jp/digitalsoul/20100712/1278886009
実践ドメイン駆動設計