DynamoDB のスロットリング — なぜ起きるのか、どう直すのか
スロットリングは、上限に触れたことを DynamoDB が伝えている状態です — ただし上限は4種類、 例外は3種類あり、ある原因への対処が別の原因を悪化させます。テーブルのキャパシティを 上げてもホットキーには何の効果もありません。オンデマンドへの切り替えもホットキーには やはり効かず、しかもオンデマンドはオンデマンド自身のルールでスロットリングし得ます。 本ガイドはその全体像です。実際に触れたのはどの上限なのか、メトリクスでどう見分けるのか、 そして原因ごとに合う対処は何か。
DynamoDB はなぜリクエストをスロットリングするのか?
文書化された理由は4つのいずれかです。1つのパーティションが、パーティションごとに固定された 1秒あたり読み取り 3,000 ユニットまたは書き込み 1,000 ユニットという上限を超えた (ホットキー — どちらのキャパシティモードでも起こります)。テーブルがプロビジョンドの RCU/WCU を超えた (プロビジョンドモード)。アカウントがリージョンレベルのスループット クォータを超えた。あるいはオンデマンドテーブルが 30 分以内に直前のピークの2倍を超えて 伸びた。対処はどれだったかで変わるので、何かのサイズを変える前に診断しましょう。
スロットリングの4つのシナリオ
AWS 自身のトラブルシューティングページ は、スロットリングをちょうど4つのケースに分けています。
- キーレンジ (パーティション) のスループット超過 — 両モード。 すべてのパーティションは 1秒あたり読み取り 3,000 ユニットと書き込み 1,000 ユニットを最大値として設計されており (パーティションキーのドキュメント)、 アイテムサイズもそこに効いてきます。テーブルレベルの設定でこれを引き上げることはできません。 分散させられるのはキー設計だけです。これが ホットパーティションのケースで、スロットリングしていても テーブルは大きく使い残しているように見え得ます。
- プロビジョンドスループットの超過 — プロビジョンドモード。 消費がテーブル (または GSI) のプロビジョンド RCU/WCU を上回り、約5分の バーストキャパシティ の緩衝も使い切った状態です。対処の段階はキャパシティ側です。 オートスケーリング、より高いプロビジョン値、あるいは モードの切り替え。
- アカウントレベルのクォータ超過。 リージョンごとのアカウントクォータが合計スループットを 制限します — デフォルトでテーブルあたり読み取り 40,000 ユニットと書き込み 40,000 ユニット、 プロビジョンドモードではアカウントあたり 80,000 RCU と 80,000 WCU です (クォータ)。 これらは初期のデフォルト値で、Service Quotas から調整でき、オンデマンドテーブルには アカウントレベルのスループットクォータはありません。
- オンデマンドの最大スループット超過。 オンデマンドは直前のピークの2倍までを即座に 受け止めます。30 分以内にその2倍を超えて伸びるとスロットリングし得ます (オンデマンドのドキュメント)。 新しいオンデマンドテーブルは、最初から1秒あたり書き込み 4,000、読み取り 12,000 を維持 できます。計画済みの段差スパイク (ローンチ、セール、移行) では、立ち上がりが緩やかである ことに賭けるのではなく、ウォームスループットでテーブルを事前にウォームしておきましょう。
3つの例外と、原因を名指しするフィールド
ProvisionedThroughputExceededException— プロビジョンドモードのキャパシティ スロットリングです。「テーブルまたは1つ以上のグローバルセカンダリインデックスについて、 許可された最大のプロビジョンドスループットを超えました」。詳細は 専用のエラーページにあります。ThrottlingException— コントロールプレーンの操作を出しすぎた場合、そしてオンデマンド テーブルでは、レートが高すぎるデータプレーンの操作全般です (2倍ピークのルールの裏にいるのは この例外です — オンデマンドのエラーページと ThrottlingExceptionを参照)。RequestLimitExceeded— アカウントレベルのスループット上限です。「AWS Support に連絡」の 領域で、そのエラーページで扱っています。
3つとも再試行可能とされており、3つとも今は「リソース + 操作 + 上限」の形をした構造化された
ThrottlingReason の値を伴います — TableReadProvisionedThroughputExceeded、
IndexWriteKeyRangeThroughputExceeded、TableWriteAccountLimitExceeded などです
(エラーリファレンス)。
例外クラスだけでなく理由を読みましょう。理由はリソース (テーブルかインデックスか)、操作の
方向、そして4つの上限のどれに触れたかを名指しします — それがそのまま診断です。ドキュメント
自身が強いる留保が1つあります。AWS のページは、アカウント上限のスロットリングが
RequestLimitExceeded として現れるのか、AccountLimitExceeded を理由に持つ
ThrottlingException として現れるのかで食い違っています。ハンドリングは理由の文字列を軸に
組み立ててください。
スロットリングされる前に負荷を吸収するもの
2つの組み込み機能が上限を和らげます。その境目を知っておくと、「昨日は動いていたのに」の説明が つきます。
- バーストキャパシティは、スパイクに備えて最大5分 (300秒) 分の未使用の読み取り キャパシティと書き込みキャパシティを保持します — ただし DynamoDB がバックグラウンドの メンテナンスのために「事前の通知なく」消費することもあり、AWS は詳細が変わり得ると明記して います。バーストを前提に設計してはいけません。運が良かった程度に扱いましょう。
- アダプティブキャパシティは、スループットを自動的かつ 即座にホットパーティションへ寄せ、高頻度でアクセスされるアイテムを独自のパーティションへ 隔離できます — ただし「トラフィックがテーブルの合計プロビジョンドキャパシティまたは パーティションの最大キャパシティを超えない限り」という条件付きです。偏りを均すだけで、 パーティションごとの 3,000/1,000 の天井を持ち上げることは決してありません。また、テーブルに LSI があるとアイテムコレクションを分割しません。現在の AWS のトラブルシューティングページが 頼りにしているのは split-for-heat (熱による分割) — 持続する熱を受けてパーティションが 分割されること — ですが、これには時間がかかり、単一のホットキーには効きません。
メトリクスから診断する
CloudWatch はリクエストとイベントを区別しており、この違いこそが診断そのものです (メトリクスリファレンス)。
ThrottledRequestsは、リクエストの中のいずれかのイベントがスロットリングされたとき、 そのリクエストを1回として数えます — GSI を3つ持つテーブルへのPutItemは、リクエストとしては 1つですが書き込みイベントとしては4つです。バッチでは、すべてのアイテムがスロットリング された場合にのみ増えます。ReadThrottleEvents/WriteThrottleEventsは、スロットリングされたイベントを1つずつ 数えます — 10 アイテムのBatchGetItemは 10 個のGetItemイベントです。GSI の書き込み スロットリングを見るには、TableNameとGlobalSecondaryIndexNameの両方を指定して メトリクスを問い合わせる必要があります — GSI バックプレッシャーがテーブルレベルの ダッシュボードから隠れるのは、これが理由です。- 新しい理由別のイベントメトリクス (
WriteProvisionedThroughputThrottleEvents、ReadKeyRangeThroughputThrottleEvents、…AccountLimitThrottleEvents、…MaxOnDemandThroughputThrottleEvents) は、同じ4つの原因でカウントを分けます — 自分の リージョンで見えるなら、「どの上限か」という問いに直接答えてくれます。
罠が1つ。SDK はスロットリングされたリクエストを自動的に再試行します — 標準のリトライモードは デフォルトで合計3回試行します (2026 年のオプトインのリトライ刷新では、DynamoDB クライアントはより短い遅延で4回試行になります)。したがって軽いスロットリングは、エラーでは なくレイテンシとして現れます。例外のログだけでなく、スロットリングのメトリクスを見てください。
GSI バックプレッシャー: 間違ったテーブルを指すスロットリング
どれか1つの GSI が書き込みの増幅を吸収できないと、「DynamoDB はデータの整合性を保つために
ベーステーブルへの書き込みをスロットリングします」
(GSI スロットリングのドキュメント)
— ベーステーブルにキャパシティの余裕があってもです。例外の ResourceArn はインデックスを
指しますが、失敗した操作はあなたのベーステーブルへの書き込みです。インデックスにはそれぞれ
独自のキャパシティ計画 (と独自のオートスケーリングポリシー)
が必要です。
GSI がベーステーブルの書き込みをスロットリングする理由
がその仕組みを追っています。
原因に合った対処を選ぶ
| 原因 | 効く対処 | 効かないもの |
|---|---|---|
| ホットキー / パーティション | 負荷を分散させるキー設計 (ホットパーティション)、split-for-heat が起きるまでの時間 | テーブルのキャパシティを上げる、オンデマンドへの切り替え |
| プロビジョンドキャパシティ | オートスケーリング、最小値の引き上げ、またはオンデマンド | リトライだけ — 負荷を増やします |
| GSI バックプレッシャー | インデックスをスケールする。スパースインデックス化や射影の見直し | ベーステーブルのスケール |
| アカウントクォータ | Service Quotas での引き上げ | テーブルレベルの設定 |
| オンデマンドの段差スパイク | 事前ウォーム (ウォームスループット)、立ち上がりを 30 分以上に分散 | 待つこと — 2倍ピークの基準はゆっくりとしか下がりません |
DynoTable でやってみる
自分で招いてしまうスロットリングの多くは、見た目より高くつく読み取りから始まります。
フィルタ付きの Scan は、いずれにせよ読み取り全量を消費します。DynoTable の実行前コスト
プレビューは、ステートメントが Query になるのか Scan になるのか、当たるインデックスは
どれか、そして消費する前の読み取りコストの見積もりを表示します — 最も安上がりな
スロットリング対策は、実行しなかった高価な読み取りです。違いは
Scan と Query のガイドで扱っています。無料の
アイテムサイズ計算ツールは、実際のアイテムを、
上記の上限が測られている単位である RCU/WCU の数値に変換します。
落とし穴と次のステップ
- リトライは過負荷を増幅します。 バックオフは SDK に組み込まれていますが、SDK の リトライの上にアプリケーション側の詰まったリトライループを重ねると、まさに苦しんでいる そのパーティションへの圧力が倍増します。
- バッチは部分的なスロットリングを隠します。
BatchWriteItemは、どれか1つでも成功して いる限り、例外を投げずに未処理のアイテムを返します — 例外だけでなくUnprocessedItemsを 確認してください。 - テーブルレベルのビューは GSI について嘘をつきます。 スロットリングイベントは必ず インデックスごとに図示しましょう。バックプレッシャーの最中でも、ベーステーブルの ダッシュボードはきれいに見えます。
- キャパシティの対処は数分、キー設計は一生もの。 オートスケーリングの反応は約5分、 クォータの引き上げにはサポートチケットが要りますが、ホットキーはどのキャパシティモードに 行ってもついてきます — 効果が積み上がるところに労力を使いましょう: パーティションキーの仕組み。
DynoTable をダウンロードして、クエリが自分のキャパシティに対して実行される前に、 それぞれの Scan と Query の実行計画と読み取りコストを確認しましょう。