概要
最近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用データを作成することができます。