CQRSとDynamoDBのデータ構造設計

先日、結婚しました。エンジニアの内山です。
今回は DynamoDB におけるデータ構造設計に関する考察を行いました。

概要

DynamoDB のデータ構造設計を行う際、RDB の設計とは異なる考え方をしなければなりません。
DynamoDB は、NoSQL であり、様々な制約があるので、色々と頭をひねる必要があり、四苦八苦しながら何とか形にしています。
そんな中、CQRS という考え方があることを知ったので、DynamoDB のデータ構造設計との関係性についてまとめてみました。

CQRSとは

CQRS は「Command Query Responsibility Segregation:コマンドクエリ責任分離」という意味で、DBへの書き込み( Command )と読み込み( Query )を別物として捉える考え方です。書き込み用と読み込み用のそれぞれの DB を分離するイメージですね。

RDBのリードレプリカに似ています。
リードレプリカでは、書き込み用 DB (マスター)と読み込み用 DB (スレーブ)があります。マスターとスレーブではデータ構造(スキーマ)は完全に同じです。
CQRS では、書き込み用と読み込み用でデータ構造が異なっていることを許容していると言えます。

DynamoDB での Command 用データ構造

DynamoDB には、以下のような特性があります。

  • トランザクション機能はあるが制限がある
    • 同時に10レコードまで。意外と超えてしまうことが多いので注意が必要
  • トランザクション内でのレコード更新はアトミック性がある

この特性を考慮すると、Command 用データ構造を設計する場合、
アトミック性を保持したいデータは、限られたトランザクション内に収められるようなデータ構造にしておく必要があります。

DynamoDB での Query 用データ構造

また DynamoDB には、以下のような特性もあります。

  • 1テーブルにつき作成できるインデックス数が限られている( GSI は20個、LSI 5個まで)
  • ソートするカラムはインデックスが貼られている必要がある( RangeKey )

これらの制約を考慮し、データの取得パターンに応じて、最適なデータ構造( Query 用データ構造)を作っておく必要があります。

例えば、以下のようなアクセスパターンがあるでしょうか。

  • ソート/検索/ページネーションを行い、データの一覧を取得する
  • グループに所属しているユーザー数を取得する(あらかじめ集計しておくなど)

Query 用の DB は DynamoDB に限らず、ElasticSearchを用いても良い場合もありそうです。

CommandデータからQueryデータへの変換について

Command データから Query データを作成する必要があります。これは例えば DynamoDB Stream 経由で、Lambda を実行して行うのが良さそうです。作成失敗した時は Lambda が再試行するので、ほぼ変換は成功させることができます。

その他の考察

どうしても厳密なトランザクション処理を行う必要がある場合は、Kinesis 経由で RDB を用いてデータを更新することも可能だと思います(Command)。
更新が成功したら、DynamoDB や ElasticSearch に Query 用データを作成することができます。

参考

【AWS re:Invent 2017 レポート】サーバレスアプリケーションのデータレイヤーの最適化 #SRV301

CQRSとイベントソーシングの使用法、または「CRUDに何か問題でも?」

DynamoDBデータモデリング虎の巻:第壱巻 〜前提知識編〜

このエントリーをはてなブックマークに追加