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

AWS データベースブログの記事 「Amazon DynamoDBによる CQRSイベントストアの構築」 を勝手に読み解く

AWS データベースブログの記事 「Amazon DynamoDBによる CQRSイベントストアの構築」 を勝手に読み解く

AWS データベースブログの記事「Amazon DynamoDBによるCQRSイベントストアの構築」を勝手に読み解くスライドです。

かとじゅん

November 28, 2022
Tweet

More Decks by かとじゅん

Other Decks in Programming

Transcript

  1.        © Chatwork CQRS Meetup 【Chatwork × ZOZO】 2022年11月25日  Chatwork株式会社

    AWS データベースブログの記事 「Amazon DynamoDBによる CQRSイベントストアの構築」 を勝手に読み解く
  2. Chatwork は日本最大級のビジネスチャットサービス 3月 リリース 30万社 突破! 20万社 突破! 導入社数34.3万社を突破! (2021年12月末日時点)

    10万社 突破! 4 ※Nielsen NetView 及びNielsen Mobile NetView 2020年6月度調べ月次利用者 (MAU:Monthly Active User)調査 ※調査対象 44サービスはChatwork株式会社にて選定
  3. DynamoDBのイベントストアで使うエンティティタイプ 13 • Aggregate ◦ ドメインオブジェクトをカプセル化する責務 • Event ◦ 何かが起こったことを示すイベント。原則的

    に不変 • Snapshot ◦ 特定の時系列ポイントまでに起こったイベン トから導出された状態を示すスナップショッ ト。スナップショットを使うとランタイムで 全てのイベントの履歴の保持やロードが不要 になる。
  4. Eventテーブル 14 • PartitionKey(PK)はWidget集約の識別子(ID) • Sort Key(SK)はイベントの時系列番号=シーケンス番号(集約単位で一意である必要がある) • WidgetCreated →

    WidgetNameChanged → WidgetDescriptionChanged • イベントのペイロードは JSON にシリアライズされた状態で保存。ProtocolBufferなどを利用する
  5. • PK = 123 and SK > event_number で Eventテーブルをクエリ

    する ④差分のイベントを読み込む 22
  6. DynamoDB Streams によるイベントストアの変更データキャプチャ 31 • Eventテーブルの変更をDynamoDB Streamsを通じて変更を取得できる ◦ 変更をキャプチャできるのは1度だけ ◦

    キャプチャ前のデータは24時間後に消える DynamoDB Application (DynamoDB Streams Client) Event をストリーム経由で読み込む
  7. • スケーラビリティを犠牲にする トランザクションをいかに避け るかという観点が盛り込まれて いる ◦ 集約が複数のイベントを発 生させた場合でも単一の書 き込みにできる ◦

    集約状態+上限数を設けた 未処理イベントの組み合わ せでWCUをキャップできる 前提) 書き込みのスケーラビリティを犠牲にしない設計戦略 33
  8. 懸念) 集約を更新しても、集約を読まないとイベントがCDCできない? 34 • 集約を更新しても、イベントは すぐにイベントテーブルに保存 されない。CDCできない? • 集約を読み出さないと、イベン トが流れない?

    集約が読まれるタイミングで EventのPutItemが起きる… イベントはAggregateテーブルに一時的に保存される イベントはAggregateテーブルから CDCする
  9. 懸念事項) リプレイ中のPutItemがコンフリクトするのでは?(図解) 36 サーバー1 getAggreateState(id=1) サーバー2 getAggreateState(id=1) Aggregate Event Event

    A { PK: 123, SK: 1, created: 1, name: WidgetCreated, payload: { name: WidgetCreated } Event A’ { PK: 123, SK: 1, created: 2, name: WidgetCreated, payload: { name: WidgetCreated } Event A’ Event A 後勝ち?イベントをCDCすると問題があ る? イベントテーブルから CDCしないのでこ の問題は無害
  10. FYI) トランザクションを使う方法もシンプル 38 • Aggregateテーブルのlast_eventsを廃止する • Aggregate + Events でTransactWriteItems(PutItem)

    + version で楽観的ロック。ただしスケーラビリティが犠牲になる サーバー1 updateAggreateState(id=1) サーバー2 updateAggreateState(id=1) Aggregate Event TransactWriteItems(PutItem) + version optimistic lock
  11. 44 チャットサービスづくり ≒ ハイトラフィックとの戦い "落とさないこと" を意識してインフラを構成 DAU 100 万人 が

    1 日平均 8 時間利用! 470万 ユーザー 突破! 1 Web アプリという枠組みではもはやなく、 仕事を支える 一種の社会基盤 というフェーズへ (サービスダウンすると災害情報に載ることも …)
  12. 45 社会基盤を見据えたアプリケーション設計 45 state Shard Shard ShardR egion RoomAggregateActor Journal

    DB (DynamoDB) SnapshotStore (S3) Message Bus RMU Read DB Read API Read API Read API Controller UseCase Write API Server Write API Server Write API Server akka-clsuter 他の MS へ logic Client ID = 1 サーバーサイド・チーム クライアントサイド・チーム リアクティブシステム と CQRS / ES を反映したアーキテクチャを採用 (クレジット決済基盤 / 銀行送金基盤 / 証券取引基盤などで実績あり) • 非同期・ノンブロッキング • スーパービジョン • 位置透過性 • ステートフル • DBとの完全な同期によって読み込み不要 • ワークロードのパーティショニング • 正規化されたデータ構造を扱う • ネットワーク分断時は一貫性を重視 コマンドサイドではドメインロジックを実行して ドメイン状態を変える機能のみを提供する クエリサイドはドメイン イベントをもとにクライアントに とって都合のよいリードモデルを 構築する • 非同期・ノンブロッキング • ステートレス • 非正規型データを扱う • ネットワーク分断時は可能性を重視 • ラムダアーキテクチャでも十分可能 MessagePosted MessageDTO PostMessage MessageDTO ID = 2 ID = 3