「DynamoDBの設計わからん」と思った時のために、設計・開発時にどのような点を考慮し検討しているかをまとめました
はじめに
こんにちは。@hayata-yamamotoです。
今回は、弊社の本番サービスでも利用している DynamoDB の設計時に、どのような点を考慮し何を検討しながらデータベースの設計を行っているかについて、実際のケースを検討しながら、現時点のまとめを皆さんに共有したいと考えています。
あくまで現時点で、チームで検討し至った結論をベースに議論を展開しますため、今後考え方が変わっていく可能性もあります。本稿では、DynamoDB の設計の正解を示すのではなく、1つの事例を示すものとしてお読みいただけますと嬉しいです。
具体的にどのようなケースについて考えるか
今回は、「ユーザーがメール配信を依頼したら、メール配信が非同期に実行され、ユーザーは配信状況が取得できる」というユーザーストーリーをテーマに、どのような設計を行っているかのイメージを持っていただければと思っています。詳細に、以下のような要件が決まっているとして、議論を進めていきます。
- 配信先はプロダクト内にいるユーザーのみ
- 配信する内容は固定のものを使用
- 配信履歴は最新のもののみ閲覧できればよく、履歴は不要(今後必要になりそう)
- 一人のユーザーが何度もメール配信を行える
なお、このユースケースは先日、弊社のプロダクトで新しく提供した機能と類似するテーマであり、実際に弊社では以下で説明するようなプロセスを経ながら、プロダクト開発(特に、バックエンド開発)を行っています。
どのように DynamoDB の設計を行っているのか
プロセスとしては大きく 3 段階に分かれます。弊社用に一部のプロセスを効率化したり端折ったりしていますが、基本的には設計時点で一度全ての設計イメージを持ち、不都合が起きる部分を後から調整していく流れで設計して行っています。
本稿は、Speaker Deck に公開されている『DynamoDB の基礎と設計』というスライドを下敷きにしています。正直、以下のスライドを見れば DynamoDB の設計がほとんどわかってしまうため、まず事前に一度目を通した上で以下の資料をお読みいただく方がスムーズかもしれません。
データモデリング
データモデリングの段階で主にやることは、ER 図の作成です。具体的にやることは以下です。
今回の場合、単純に以下のようなエンティティ定義とします。
ただし、ER 図を必ず私もテーブル定義としては使用せず、あくまで取り扱うデータや概念の関係性を整理するために作成しているという認識でいるのが重要です。ここが RDB に慣れていると最も苦しいところですが、ER 図を書いたらテーブルと対応させて考えてしまうマインドセットを切り替えられると、DynamoDB が楽しくなってくると思います。テーブル定義と対応させないのは、DynamoDB の表現力を活かすためでもあり、ビジネスの要求やユースケースに必要十分な開発をするためでもあります。
アクセスパターンの決定
次に、ユーザーストーリーをベースに、「実際のユーザーがどのようにシステムを利用するか?」にフォーカスを当てながら、ユースケースを整理していきます。具体的には、以下のようなことをしています。
今回の例で言うと、REST API を念頭に設計を行っており、クライアントサイドのユースケースに合わせたエンドポイントを用意するのではなく、リソースベースに設計を行う例となっています。この場合は、バックエンド内部のビジネスロジックの一部としてユースケースをみなしてしまう方がシンプルです。もし、GraphQL と DynamoDB を組み合わせて使用している場合は GraphQL フィールドとユースケースが 1:1 となるような設計が望ましいかもしれません。[1]
上記をベースに作成するユースケースは以下のようになります。
エンティティ | ユースケース |
---|---|
User | アイテムの単一取得 |
User | アイテムの一括取得 |
Notification | アイテムの単一取得 |
Notification | アイテムの作成 |
Notification | ステータス情報の更新 |
テーブルとインデックス、クエリの決定
ER 図とシーケンス図をベースに、「実際に、どのようなテーブルを定義するか」を決定します。具体的には以下のようなことをしています。
今回は、以下のような TypeScript の型となるように API を定義するとして、テーブル定義とインデックスを設計しました。
type PostRequestBody = {
name: string;
};
type Response = {
id: string;
to_user_id: string;
to_user_name: string;
from_user_id: string;
from_user_name: string;
status: "IN_PROGRESS" | "COMPLETED" | "FINISHED";
createdAt: number;
createdBy: string;
updatedAt: number;
updatedBy: string;
};
テーブル定義
クエリ設計
終わりに
今回は、弊社の本番サービスでも利用している DynamoDB の設計時に、どのような点を考慮し何を検討しながらデータベースの設計を行っているかについて、実際のケースを検討しながら、現時点のまとめを皆さんに共有しました。正直、DynamoDB のポテンシャルをまだまだ発揮しきれているとは思っていませんが、「こんな感じで開発してるのね」と伝わっていれば嬉しいです。
DynamoDB やこの設計、検討プロセス自体ももっと改善していきたいと考えており、知見とご経験を持っていらっしゃる方を探しております!もし、この記事や弊社に少しでもご興味持っていただけたら、是非カジュアル面談などにお越しください!
参考
- https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/best-practices.html
- https://qiita.com/_kensh/items/2351096e6c3bf431ff6f
- https://pages.awscloud.com/rs/112-TZM-766/images/20190905_イチから理解するサーバーレスアプリ開発-サーバーレスアプリケーション向きのDB 設計ベストプラクティス.pdf
Discussion