はじめに
以前、DynamoDBを使うなら最初に設定しておきたい5つのポイントという記事を書きました。
前回の記事では、
- ポイントインタイムリカバリ(PITR)を有効にする
- Auto Scaling(またはオンデマンド)を設定する
- TTL(Time To Live)を設定する
- CloudWatchで監視する
- バックアップを設定する
という、DynamoDBを使い始める際にまず設定しておきたい5つのポイントを紹介し、それぞれの設定手順は別記事(#1〜#5)でも詳しく解説しました。
ただ、前回はあくまで「何を設定すればいいか」という運用の入り口の話が中心で、
- 「そもそもパーティションキーの設計を間違えると、Auto Scalingを設定しても解決しない問題があるらしい」
- 「オンデマンドとプロビジョンド、結局どっちが安いのか」
- 「DAXってキャッシュらしいけど、ElastiCacheと何が違うのか」
といった、もう一歩踏み込んだ設計・仕組みの部分には触れていませんでした。そこで今回は、前回の記事からもう一歩踏み込んで、DynamoDBの設計・容量まわりの仕組みを調べてみました。
この記事はこんな方におすすめ
- 前回の記事で最初に設定すべきポイントは分かったので、もう少し設計の仕組みを知りたい方
- パーティションキーの設計やホットパーティション問題について知りたい方
- オンデマンドとプロビジョンドの選び方で迷っている方
- DAXがどういう仕組みでDynamoDBを高速化しているのか知りたい方
- GSI(グローバルセカンダリインデックス)の注意点を知りたい方
まず前回のおさらい
前回の記事のポイントを簡単に振り返ります。
テーブル作成
↓
PITRを有効化(誤削除・誤更新に備える)
↓
Auto Scaling または オンデマンドを設定(性能とコストのバランス)
↓
TTLを設定(不要データの自動削除)
↓
CloudWatchで監視(スロットリングの検知)
↓
バックアップを設定(PITRとは別の備え)
- PITRは35日以内なら任意の時点にテーブルを復元できる機能で、最優先で有効化すべき設定
- オンデマンドは開発環境や利用量が読めないサービス向き、プロビジョンド+Auto Scalingは本番環境やアクセス数が予測できるシステム向き
- TTLで不要なデータを自動削除でき、ストレージ料金の削減にもつながる
- CloudWatchでThrottle(スロットリング)が発生していないか定期的に確認する
前回は、この「Auto Scalingを設定すれば安心」という説明で終わっていましたが、実はその前提として、パーティションキーの設計が適切であることが重要だと分かったので、今回はそこから深掘りしていきます。
パーティションキー設計をもう少し深掘りしてみた
DynamoDBは内部的に、テーブルのデータを複数の「パーティション」に分散して保存しています。
DynamoDBテーブル
↓
パーティションキーのハッシュ値をもとに分散
↓
┌───────────────┬───────────────┬───────────────┐
│ パーティション1 │ パーティション2 │ パーティション3 │
└───────────────┴───────────────┴───────────────┘
調べてみると、この1つのパーティションが処理できるスループットには、明確な上限があることが分かりました。
| 項目 | 上限(1パーティションあたり) |
|---|---|
| 読み込み | 3,000 RCU |
| 書き込み | 1,000 WCU |
つまり、テーブル全体でどれだけAuto Scalingを設定していても、特定のパーティションキー(例えば「特定の日付」や「特定のユーザーID」)にアクセスが集中してしまうと、そのパーティション単体の上限に引っかかってスロットリングが発生してしまいます。これがいわゆる「ホットパーティション問題」です。
悪い例:パーティションキーが「日付」だけの場合
↓
その日のアクセスが「2026-09-13」という1つのパーティションキーに集中
↓
1パーティションの上限(3,000RCU/1,000WCU)に到達
↓
テーブル全体のキャパシティに余裕があってもスロットリングされる
これを避けるため、よく紹介されているのが「シャーディングキー」を使う設計です。
良い例:パーティションキーに分散用のサフィックスを付与
↓
"2026-09-13#0" "2026-09-13#1" "2026-09-13#2" ... のように分散
↓
複数のパーティションにアクセスが分かれる
↓
特定パーティションへの集中を回避
なお、DynamoDBには「アダプティブキャパシティ」という、アクセスが偏っているパーティションに自動で容量を再配分してくれる仕組みもありますが、これも1パーティションあたり3,000RCU/1,000WCUという上限そのものを超えられるわけではない、という点は誤解しないよう注意が必要だと感じました。前回紹介した「Auto Scalingを設定する」というのはあくまでテーブル全体(またはGSI)のキャパシティの話であり、パーティションキーの設計が悪いとAuto Scalingだけでは根本解決にならない、というのが今回の大きな発見でした。
オンデマンドとプロビジョンド、結局どっちが安いのか
前回は「開発環境ならオンデマンド、本番はプロビジョンド+Auto Scaling」という紹介にとどまっていたので、もう少し具体的な違いを調べてみました。
| 項目 | オンデマンド | プロビジョンド+Auto Scaling |
|---|---|---|
| 課金方式 | 実際に消費したRCU/WCUに対する従量課金 | 設定したキャパシティに対する課金(未使用分も課金) |
| 単価 | プロビジョンドより高め | オンデマンドより安め |
| アクセス予測 | 不要 | ある程度必要(Auto Scalingが追従するまでにタイムラグがある) |
| 急激なスパイクへの追従 | 即座に対応しやすい | Auto Scalingのスケール判断・実行に数分かかる場合がある |
| デフォルトの上限 | テーブルあたり読み書きそれぞれ40,000(アカウントのサービスクォータ) | 設定次第 |
2024年5月には、オンデマンドテーブルでも上限スループットを個別に設定できる「Configurable Maximum Throughput」という機能が追加され、意図しない急増によるコスト増を抑えられるようになったことも分かりました。また同じく2024年11月には「Warm Throughput」という機能が追加され、テーブルやインデックスが過去の利用実績に基づいて「瞬時にどれくらいのスループットに耐えられるか」を可視化・事前に引き上げておけるようになっています。急なトラフィック増加が予想される場合は、事前にWarm Throughputを引き上げておく(プレウォーミング)ことで、10倍・100倍規模のアクセス増にもスロットリングなく耐えられる、と紹介されていました。
大雑把な目安としては、
アクセス量が安定していて予測できる
↓ Yes
プロビジョンド + Auto Scalingの方がコストを抑えやすい
アクセス量が読めない・スパイクが激しい
↓ Yes
オンデマンドの方が運用がシンプルで安全
という判断軸になりそうですが、実際にはコストシミュレーションを行った上で選ぶのが確実だと感じました。
DAX(DynamoDB Accelerator)を調べてみた
前回の記事で紹介した「CloudWatchで監視する」の先の話として、読み込みが多いテーブルの負荷を減らす方法としてよく紹介されるのがDAX(DynamoDB Accelerator)です。
アプリケーション
↓
DAXクラスタ(インメモリキャッシュ、DynamoDBと互換のAPI)
↓ キャッシュヒット:マイクロ秒オーダーで応答
↓ キャッシュミス:DynamoDB本体へ問い合わせ
DynamoDB
DAXの特徴として調べて分かったのは、次のような点です。
- DynamoDBのAPIとほぼ互換性があるため、エンドポイントを差し替えるだけで導入しやすい
- 結果整合性のある読み込みを、ミリ秒単位からマイクロ秒単位まで高速化できる
- キャッシュヒットした分はDynamoDB本体へのRCU消費を抑えられるため、コスト削減にもつながる
- 強力な整合性のある読み込み(Strongly Consistent Read)はDAXを経由してもDynamoDB本体に直接問い合わせが行われる
似たような立ち位置のサービスにElastiCache(RedisやMemcached)がありますが、DAXは「DynamoDB専用に最適化されたキャッシュ」であり、DynamoDBのAPIをそのまま使える点、書き込みも透過的にキャッシュへ反映してくれる点が大きな違いだと感じました。汎用的なキャッシュ基盤が欲しい場合はElastiCache、DynamoDB専用でとにかく手間なく高速化したい場合はDAX、という使い分けになりそうです。
GSI(グローバルセカンダリインデックス)の注意点
前回は触れていませんでしたが、DynamoDBを設計する上で欠かせないのがGSI(グローバルセカンダリインデックス)です。パーティションキー以外の項目で検索したい場合に使いますが、調べてみるといくつか注意点がありました。
- GSIは実質的に「別テーブル」のような存在で、GSI自体にも独自のキャパシティ(RCU/WCU)が必要
- 元のテーブルへの書き込みは、非同期でGSI側にも反映される(結果整合性)
- GSI側のパーティションキー設計が悪いと、GSI側でホットパーティション問題が発生し、元テーブルへの書き込み自体がスロットリングされることがある
テーブル書き込み
↓
GSIへの反映(非同期)
↓ GSI側のキャパシティ不足やホットパーティションが発生すると…
テーブル本体への書き込みまで影響を受ける場合がある
前回紹介したAuto Scalingやオンデマンドの設定は、GSIに対しても個別に有効化・設定できるため、「テーブル本体は十分な容量なのに、GSI側がボトルネックになっている」というケースは、運用開始後に見落としがちなポイントだと感じました。
DynamoDB Streamsをもう少し深掘りしてみた
前回「余裕があれば設定したい項目」として軽く紹介したDynamoDB Streamsについても、内部の仕組みを調べてみました。
テーブルへの変更(Insert/Update/Delete)
↓
Streamにイベントとして記録(シャードに分散)
↓
Lambdaのイベントソースマッピングがシャードを読み取る
↓
Lambda関数がイベントを処理
Streamsは内部的にKinesis Data Streamsに似たシャード構造を持っており、書き込みが増えるとシャードが自動的に分割される、という点が分かりました。また、Streamに記録されたイベントは24時間しか保持されないため、Lambdaの処理でエラーが続くとイベントが失われる可能性があり、DLQ(デッドレターキュー)や十分なリトライ回数の設定が重要になる、という注意点も見かけました。
実務での注意点
ここまで調べてみて、実際にDynamoDBを設計・運用する際に気をつけたほうがよさそうな点をまとめておきます。
- パーティションキーの分散設計:日付やステータスなど値の種類が少ない項目だけをパーティションキーにせず、必要に応じてシャーディングキーを組み合わせる
- GSIのキャパシティも個別に監視:テーブル本体だけでなく、GSIごとのスロットリングメトリクスもCloudWatchで確認する
- Warm Throughputの活用:大規模なキャンペーンやリリースなど、事前にアクセス増が予想される場合は、事前にWarm Throughputを引き上げておく
- DAX導入時の整合性要件の確認:強力な整合性が必須の処理がある場合は、DAXを挟んでも整合性モデルが変わらないかを設計時に確認する
- Streamsの保持期間とエラー処理:24時間という保持期間を踏まえて、Lambda側の再試行設定とDLQを必ずセットで設計する
個人的に調べてみて思ったこと
前回は「最初に設定しておきたい5つのポイント」という運用の入り口を紹介するところまででしたが、今回もう一歩踏み込んでみると、
- Auto Scalingやオンデマンドを設定していても、パーティションキーの設計が悪ければホットパーティション問題は解決しないこと
- オンデマンドとプロビジョンドの選択は、単純な「本番か開発か」ではなく、Warm ThroughputやConfigurable Maximum Throughputといった新しい機能も踏まえて判断する必要があること
- DAXは「DynamoDB専用に最適化されたキャッシュ」であり、ElastiCacheとは役割が異なること
- GSIは実質的に別テーブルのような存在で、GSI側のボトルネックがテーブル本体に影響することがあること
が分かりました。特に、「テーブル全体のキャパシティに余裕があっても、パーティション単位の上限でスロットリングされる」という話は、前回の「Auto Scalingを設定すれば安心」という理解を、良い意味で裏切られる発見でした。DynamoDBは設定すれば終わりではなく、パーティションキーの設計とセットで考える必要があるサービスなのだと実感しました。
まとめ
今回は、DynamoDBの設定ポイントについて、前回の記事よりもさらに深掘りしてみました。重要なポイントをまとめると、
- 1パーティションあたりの上限は読み込み3,000RCU・書き込み1,000WCUで、Auto Scalingを設定してもこの上限は超えられない
- パーティションキーの設計が悪いとホットパーティション問題が発生し、シャーディングキーなどの対策が必要になる
- オンデマンドとプロビジョンドの選択には、Warm ThroughputやConfigurable Maximum Throughputといった比較的新しい機能も関わってくる
- DAXはDynamoDB専用のインメモリキャッシュで、応答時間をミリ秒からマイクロ秒に短縮できる
- GSIは別テーブルのような存在であり、GSI側のキャパシティやパーティション設計もあわせて監視・設計する必要がある
前回は「最初に何を設定すればいいか」というチェックリストのレベルで終わっていましたが、今回はその設定の前提となる設計そのものまで掘り下げることができました。まだ実際に自分の手でホットパーティションを再現したり、DAXを導入して応答速度を計測したりはできていないので、今後は手を動かしながら検証していきたいと思います。
同じようにDynamoDBの設計に興味がある方の参考になれば幸いです。
最後まで読んでいただき、ありがとうございました!
参考
- DynamoDB burst and adaptive capacity - Amazon DynamoDB
- Amazon DynamoDB introduces configurable maximum throughput for on-demand tables
- Amazon DynamoDB introduces warm throughput for tables and indexes
- Understanding DynamoDB warm throughput - Amazon DynamoDB
- DynamoDB Accelerator (DAX) とインメモリアクセラレーション - Amazon DynamoDB
- DynamoDB maximum throughput for on-demand tables - Amazon DynamoDB