野中のre:Invent 2024 1 日目:DynamoDBデータモデリングのポイント

こんにちは。クラウドネイティブ技術部の野中です。

今年の12月2日から12月6日にかけて開催される re:Invent 2024 に現地参加しています!
このイベントには以前から参加したいと思っていたので、ついに念願が叶い、ワクワクが止まりません。

今回は、DynamoDBデータモデリングに関するセッションを受講しました。このテーマを選んだのは、実際の案件でもDynamoDBを採用している中で、自身の知識不足を感じる場面があったためです。セッションを通して得た内容を振り返りながら、皆さんと共有していきたいと思います。

1. DynamoDBとは?

DynamoDBは、AWSが提供するNoSQLのキーバリューストアおよびドキュメントデータベースです。スケーラビリティや低レイテンシを重視した設計で、以下のような特長を持ちます。

  • オンデマンドスケーリング: トラフィック量に応じて自動で容量を調整。※オンデマンドキャパシティモードの際
  • マルチAZ(アベイラビリティゾーン)レプリケーション: 高可用性を確保。
  • 数ミリ秒単位のレイテンシ: 高速クエリ処理。

ユースケースとしては、ゲーム、チャットアプリ、IoTデータ管理、商品カタログなど、多種多様なアプリケーションに利用されています。

2. 電話帳で理解するデータ設計とポイント 3 選

本セッションではDynamoDBの基本的なデータ構造を電話帳に例えて説明していました。 以下のような形です。

i. パーティションキー(PK)とソートキー(SK)

  • PK: 電話帳における「都市名」
  • SK: 都市内での「姓と名」

例として、次のように設計できます。

PK(都市名) SK(姓と名) 電話番号 郵便番号
東京 山田#太郎 03-1234-5678 100-0001
東京 佐藤#花子 03-9876-5432 100-0002
大阪 高橋#一郎 06-1122-3344 530-0001

DynamoDBでのクエリ例

都市内の全データを取得

   response = table.query(
       KeyConditionExpression=Key('PK').eq('東京')
   )

→ 東京に登録されたすべてのユーザー情報が取得されます。

特定の人物を検索

response = table.query(
    KeyConditionExpression=Key('PK').eq('東京') & Key('SK').eq('山田#太郎')
)

→ 山田太郎さんの詳細が返されます。

ii. 効率的な検索を可能にするインデックス

DynamoDBでは、ローカルセカンダリインデックス(LSI)とグローバルセカンダリインデックス(GSI)を使って複数の検索軸を提供します。

例えば、「東京」のデータを電話番号順で取得したい場合です。

設計例

  • PK: 都市名
  • 新しいSK: 電話番号
PK(都市名) SK(電話番号) 姓と名 郵便番号
東京 03-1234-5678 山田#太郎 100-0001
東京 03-9876-5432 佐藤#花子 100-0002

特徴とポイント

  • 部分的な並び替えが可能: 同じ都市内で柔軟にデータを取得。
  • テーブル作成時のみ設定可能: 設計段階での計画が必要。

iii.GSI: 新しい検索軸を作る

どんなときに使う?

例えば、「郵便番号」をキーにデータを検索したい場合です。

設計例

  • 新しいPK: 郵便番号
  • 新しいSK: 都市名 + 姓と名
PK(郵便番号) SK(都市名#姓と名) 電話番号
100-0001 東京#山田#太郎 03-1234-5678
100-0002 東京#佐藤#花子 03-9876-5432
530-0001 大阪#高橋#一郎 06-1122-3344

特徴とポイント

  • 新しい検索条件を追加可能: 郵便番号など、元のテーブルにない検索軸を提供。
  • 設定は後からでもOK: テーブル作成後に追加可能。
  • 注意点: 遅延やコスト増加に注意が必要。

3. スケーラブルでコスト効率の高い設計

DynamoDBの設計では、スケーラビリティコスト効率を両立するための工夫が求められます。以下に、具体的な実践例と最適化の方法を紹介します。

i. ライトシャーディング

  • 目的: 特定のパーティションにトラフィックが集中するのを防ぎ、読み書きの負荷を均等化する。
  • 方法: PKにランダムな接尾辞を付加してデータを分散。
  • : 東京#0, 東京#1 のようにシャードを分けることで、負荷を複数のパーティションに分散。
  • 注意点: シャードキーの管理にはアプリケーション側の工夫が必要。クエリの際にどのシャードを参照すべきかを適切に判断する仕組みを設ける必要があります。また、シャードキーをランダムに割り振ると範囲クエリが難しくなるため、アクセスパターンに応じて計画的に設計する必要があります。

ii. パーティション分割

  • 目的: データ量やトラフィックが増加した場合に、パフォーマンスを維持する。
  • 仕組み: DynamoDBは内部的に自動でパーティションを分割し、スループットキャパシティを拡張。
  • 注意点: パーティション分割が頻繁に発生する場合、アクセスパターンを見直すことで無駄なスケーリングを抑制できます。

コスト最適化の具体策

i. 静的データと動的データの分離

  • 目的: 頻繁に変更されないデータを分離することで、書き込みコストを削減。
  • :
    • 静的データ: 住所やユーザーの基本情報(ほとんど更新されない)。
    • 動的データ: 購入履歴やセッションデータ(頻繁に更新)。
  • 実践例: 静的データを独立したアイテムまたは別テーブルに保存することで、書き込み単位を効率化。

ii. データの圧縮

  • 目的: 項目サイズを削減し、ストレージコストと書き込み容量単位(WCU)を最適化。
  • 方法:
    • 項目データを圧縮(例: gzip)して保存。
    • 圧縮されたデータはバイナリ形式でDynamoDBに格納可能。
  • 注意点: 圧縮データを利用する場合、アプリケーション側で解凍処理を追加する必要があります。また、圧縮しても最大項目サイズ(400KB)を超える場合、データの分割やS3との併用を検討する必要があります。

4. まとめ

DynamoDBは、高いスケーラビリティと柔軟性を持つNoSQLデータベースとして、さまざまなユースケースで利用されています。本記事では、以下のポイントを解説しました。

i. DynamoDBの基本特徴

オンデマンドスケーリングやマルチAZレプリケーション、高速なクエリ処理などの利点を活かすことで、信頼性の高いシステムを構築できます。

ii. 電話帳モデルでのデータ設計

PK と SK の設計を電話帳の例で説明しました。DynamoDBの効率的なクエリ設計には、適切なキー構造が重要です。

iii. インデックスを活用した柔軟な検索

LSIとGSIを使うことで、既存のデータモデルに柔軟な検索機能を追加可能です。これにより、異なる観点からデータを効率よく取得できます。

iiii. スケーラブルでコスト効率の高い設計

ライトシャーディングやパーティション分割で負荷を分散させつつ、静的データと動的データの分離やデータ圧縮でコスト削減を実現する方法を紹介しました。

DynamoDBを使いこなすための次のステップ

  • 設計段階での計画を徹底: アクセスパターンを考慮し、キー設計やインデックスの利用方法を明確化しましょう。
  • コストとスケーラビリティのバランスを最適化: ライトシャーディングやデータ分離を活用し、効率的な設計を心がけましょう。

DynamoDBは、設計次第でそのパフォーマンスを最大限に引き出すことができるデータベースです。今回の記事が、皆さんのプロジェクトに役立つヒントになれば幸いです。