Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CQRSはEvent Sourcingなしで実現できるのか?

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

CQRSはEvent Sourcingなしで実現できるのか?

Avatar for かとじゅん

かとじゅん

March 24, 2020
Tweet

More Decks by かとじゅん

Other Decks in Programming

Transcript

  1. © Chatwork あなたは誰? • 加藤潤一(@j5ik2o) • Chatwork社のテックリード • 直近の活動 ◦

    Kafka, S3のEvent Sourcingする ためのプラグインを開発 ◦ Fargateを使った負荷試験ツール の開発
  2. © Chatwork CQRS • Command and Query Responsibility Segregation(CQRS責務分離) ◦

    2010年 Greg Young氏 • CQS(Command-Query Separation) をアーキテクチャレベルに適用 • CommandとQueryで要件が違うから わける ◦ 一貫性(強い or 弱い) ◦ データ形式(正規化 or 非正規化) ◦ スケーラビリティ(C:Q=2:8)
  3. © Chatwork FYI: C/Qを分離しない場合の弊害 • リポジトリのクエリメソッドが複雑になる ◦ employeeRepository.findByDeptIdsWithEmpNamesWith…(…, …, …)

    • N+1クエリが発生しやすい reservationRepository.findByIds(ids).map { reservation => val a = hotelRepository.findById(reservation.hotelId) val b = customerRepository.findById(reservation.customerId) readModelDto(a, b) } • オブジェクト→DTO変換が非効率 ◦ DTOに変換するときに、UIに合わせて捨てられる項目がある
  4. © Chatwork FYI: リードモデルの形式変換をしない場合の問題 • 例えば、入社日がEpocTime(Long値)として保存される場合、そのまま ではクエリのレスポンスに含めることができない。しかしクエリ側から 値オブジェクトに依存ができない。 • これを回避するためにRMUで事前に形式変換する必要がある

    Attribute Type Value EmployeeId String “123456789” JoinedDate Long 1585039714572 ... ... .. JoinedDate#asFormattedString 2020年03月24日 08:48 内部データ表現を意味のある値表現にするにはドメ インオブジェクトを使う必要がある エンコードされたドメインオブジェクト リードしたい値表現
  5. © Chatwork C/Qのモデル間の変換・同期の問題はイベントで解決 “The model that is best suited is

    the introduction of events, events are a well known integration pattern and offer the best mechanism for model synchronization.” by Greg Young 最も適したモデルはイベントの導入であり、イベントは よく知られた統合パターンであり、モデルの同期化に最 適なメカニズムを提供します。
  6. © Chatwork CQRS+Event Sourcing • 真のデータソースは永続されたイベ ント • そのイベントを使ってリードモデル を構築する

    Event Sourcingは大袈裟で大変と いう意見を聞くので、他の方法がな いか考えてみた
  7. © Chatwork アプリケーションからのイベント伝搬方式の問題 • イベントは全順序に並んでいないとうまくリードモデルを構築できない • ステートレスなアプリケーションでは、2層コミット問題とイベント追い 越し問題が起きる (参考文献) スターバックスは2フェーズコミットを使わない

    https://code.google.com/archive/p/gregors-ramblings-ja/wikis/18 _starbucks.wiki 最新状態を保存する DBとキューのトランザク ションを同一化しないと防ぐのが難しい。もしくは DB書き込み成功後にエンキューするプロセスを シャーディングする必要がある
  8. © Chatwork まとめ • 単純にイベントを伝搬させるだけでは問題が生じる • ステートレスなウェブアプリケーションでは、 CDC+Outbox方式を採用したほうが無難 • CDC+Outbox方式は、トランザクションログが真の

    データソースでありESの一種であるという理解が必要 • 外形的にはCQRS+SSはできるように見えるが、真の データソースは最新データにはならない。結局はESに 帰結する