メメメモモ

プログラミング、筋トレ、ゲーム、etc

CQRSとDynamoDBのデータ構造設計

概要

最近DynamoDBで設計を行っています。DynamoDBはNoSQLであり様々な制約があるので、RDBの設計とは異なる考え方をしなければなりません。

四苦八苦しながら、設計をしていて何とか形になってきています。そんな中、CQRSという考え方があることを知りました。自分が何となくやっていたことと近いこともあり、一度CQRSとDynamoDBのデータ構造設計についてまとめてみました。

CQRSとは

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

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

DynamoDBでのCommand用データ構造

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

  • NoSQLなのでRDBのようなトランザクションがない
    • 複数レコードにまたがる更新にアトミック性を保持することができない
  • 1レコードの更新はアトミック性がある

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

DynamoDBでのQuery用データ構造

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

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

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

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

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

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

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

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

その他の考察

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

参考

www.yumemi.co.jp

postd.cc

marcy.hatenablog.com