Slide 1

Slide 1 text

ざっくり CQRS/Event Sourcing を解説する かとじゅん(@j5ik2o) 設計ナイト2020

Slide 2

Slide 2 text

DDDに関係はしますが、 ドメインモデルそのものではなく 分散システムの設計パターンについて 話します

Slide 3

Slide 3 text

誰? ● Chatworkで仕事してます。現在は分散システムの設計・実装を担当しています。 ● 2016年からk8s+Akka+Kafka+HBaseを用いた、CQRS/Event Sourcingシステム を運用しています。 ● 現在もAkka-Clusterへのマイグレーションを計画中

Slide 4

Slide 4 text

DDDによるクエリサイドのペインについて これらのペインを飲み込めるの であれば、CQRSを採用する 必要はない

Slide 5

Slide 5 text

C/Qの独立した最適化ができないか? それがCQRSだ

Slide 6

Slide 6 text

CQRSとは ● Command and Query Responsibility Segregation=コマンド・クエリ責務分離 ○ (2010年 Greg Young氏) ● コマンドとクエリをスタックごと隔離すること。単なるモデルの分離ではない。Event Sourcingとセットで採用されることが多い。 ● Greg Young氏の論文でも隔離のための境界があると明示されている ● コマンドはDDDのドメインモデルを内包することを想定している。というか、DDDの ために考えられたパターン。CQRSである=DDDを採用していることになる。 ● モデルだけ分離して、隔離の境界がないものはCQRSと呼んではいけない(個人の 解釈) とはいえ、CQRSですべてが解決されるわけではない

Slide 7

Slide 7 text

CQRS/Event Sourcingのイメージ スナップショット ストレージ 必要に応じてVOを使ってリード モデルを構築する

Slide 8

Slide 8 text

イベントをどう使うのか ● 理解を促すための擬似コー ド。CRUDよりレイテンシが悪 化する例なので真似しないよ うに…。 ● エンティティのライフサイクル をリクエストスコープから分離 する必要がある。そのために Actorを使う

Slide 9

Slide 9 text

「えっ、複雑やんけっ…」 一旦落ち着こう

Slide 10

Slide 10 text

なぜC/Qをわけるのか ● そもそもCとQで要件が異なるので、混ぜないで隔離するほうが望ましい。 ● ただし、データ形式がクライアント要求に合わせる必要がなければC/Qを分けなくて もよい。そういう案件に巡り会えたことがないが…。 コマンド クエリ 一貫性/可用性 一貫性重視。最新の書き込みが反映され るなければならない。トランザクション整合 性(強い整合性)を使う 可用性重視。つまりちょっと古いデータ見 えてもよい。結果整合性 (弱い整合性)を使 う データ形式 正規化されたデータを保存する (集約単位 ≒概念単位) 非正規化されたデータ形式取得する (クラ イアント要求に合わせる ) スケーラビリティ 全体のリクエストに対して少ない比率。必 ずしもスケーラビリティは重要ではない 全体のかなりのリクエスト比率を占めるた め、スケーラビリティが必要

Slide 11

Slide 11 text

CQRSの利点と欠点 ● 利点 ○ コマンドとクエリに分離されており独立しているため、耐障害性を確保しやす く、デプロイサイクルも別にできる ○ コマンドとクエリを必要に応じて個別に最適化できる。別々にスケールさせるこ とができる ● 欠点 ○ コストがかかる。目的ごとにスタックを分離するので、構成要素が多くなる。 ○ CQRSは従来と比べると複雑と揶揄されることが多いが、従来モデルではC/Q が混在することの複雑があったが、CQRSではある意味シンプルになってい る。が全体の構成要素は複雑なる。 ■ つまり、単体のオブジェクトとしてはシンプルになるが、ネットワークとして は複雑になるということ

Slide 12

Slide 12 text

● CQRSでは、ドメインオブジェクトはドメインロジックを実行するためのシンプルなモデ ルとなる。ただし、全体の構造は複雑になる CQRSでモデルがどう変わるか メッセージの本文を持 つのはつらい メッセージの本文を保 持しなくてよい

Slide 13

Slide 13 text

非Event SourcingでのCQRSはいろいろ難しい ● ドメインオブジェクトが計算する値 はそもそも永続化されていない。 その値がリードモデルで必要な 場合、DBトリガで更新を通知して SQLでリードモデルを構築できな い ● リードモデル更新プロセスを採用 する場合、DBとは別途キューを 必要とする。結局Eventに頼るこ とになる。 ● できるだけダブルコミットを避けて、障害でノードが消失しても再開できるようにイベント は永続化される必要がある。Event Sourcingではイベントを真のデータソースにす る。 スケーラビリティの観点でポーリ ングが難しいので、 pub/subを利 用する

Slide 14

Slide 14 text

CQRS/ES対応分散システムフレームワーク ● Akka https://akka.io (Scala, Java) ● Akka.NET https://getakka.net/ , https://akkatecture.net/ (.NET) ● proto.actor https://proto.actor/ (Golang, .NET, Java/Kotlin) ○ リアクティブシステムが作れそうなのは Golangのみ 11k starts, 2010~ 3.3k starts, 2016~ 3.7k starts, 2014~

Slide 15

Slide 15 text

完全にC/Qを分けるのは無理… クエリサイドのペインも 許容できないんだけど…

Slide 16

Slide 16 text

境界を引かない=非CQRSにする(現実解) ● クエリでは一切リポジトリを利用しない。ただしVOに依存することがある ● リポジトリはドメインロジックのために使う(findById, store, deleteのみ)

Slide 17

Slide 17 text

FYI: Scala/Akkaを学ぶための薄い本を売ってます ● Scala 2.13とAkka 2.6(Akka-Typed)で解説しています。 10冊売れた 29冊売れた