中級読了 3 分

DynamoDB のホットパーティション:見つけ方と直し方

DynamoDB は、それぞれが独自のスループット枠を持つ多数の物理パーティションにデータを 分散します。ホットパーティション とは、1つのキーが自分の枠でさばける以上の読み取りや 書き込みを大量に引き寄せることです — その結果、そのキーへのリクエストがスロットルする 一方で、テーブルの残りは遊んでいます。

DynamoDB のホットパーティションとは?

DynamoDB のホットパーティションとは、1つの が、 そのスループット枠でさばける以上の読み取りや書き込みを大量に吸収し、そのキーへの リクエストがスロットルする一方でテーブルの残りが遊んでいる状態です。原因はテーブルの サイズではなくキー設計 — セレブアイテム、カーディナリティの低いキー、今日の日付 — です。 対処は書き込みを分散させることです。

  • 原因はキー設計であって、テーブルサイズではありません。 1つの にトラフィックが集中すること — 人気ユーザー、 status="OPEN" フラグ、今日の日付 — が罠です。
  • アダプティブキャパシティは助けにはなりますが、解決策ではありません。 DynamoDB は 熱を自動的に再分配しますが、それでも単一のアイテムや単一のキーが、1つのパーティションで さばける量を超えることがあります。
  • 対処は書き込みを分散させることです。 キーにエントロピーを加える(ライトシャーディング)か、 ホットな読み取りパスを、より分散したアクセスパターンへ移します。
  • SQL から来ると、これに相当するものがありません。 リレーショナルテーブルには 「ある行のインデックス値が人気すぎる」という概念がありません — DynamoDB の キーごとにフラットなスループットというモデルにはあるのです。

そもそもなぜパーティションが存在するのか

DynamoDB は、単一ノードの SQL モデルをパーティション分割された水平スケールのモデルへと 交換した、2007年の Amazon Dynamo 論文の実運用上の後継です。データは パーティションキー のハッシュによって、物理ストレージノード全体にシャーディングされます。

各パーティションは有限量のデータを保持し、有限量のスループットをさばきます。AWS は、 1パーティションあたり毎秒 3,000 の読み取りユニットと 1,000 の書き込みユニット という ハードな上限を文書化しています (AWS — パーティションの挙動)。 課金モードを変えてもこの物理的な上限は上がりません。変わるのは、テーブルレベルの支出がどう 計測されるかだけです。テーブルレベルのコストには料金計算ツールを、 スロットルがパーティション起因かテーブル起因かを見るには Contributor Insights を使ってください。

その上限がすべてを物語ります。テーブルの スループットは、 全パーティションにわたる合計です。あるキーのアイテムコレクションは1つのパーティションで 始まり、熱による分割(split-for-heat)がそれをソートキーの境界で複数に切り分けることが できます — ただし、テーブルに LSI があるか、ソートキーが単調増加している場合は、 1つのパーティションに固定されます。

罠に名前をつける: 1つのキーに積み上がるトラフィック

スループットが均等に共有されるのは、アクセスがキー全体に均等に分散している場合に限り ます。1つのキーが不均衡なトラフィックを受けた瞬間、そのキーだけがスロットルし、 テーブル全体のキャパシティは使われないまま残ります。

典型的なホットキーの形:

  • セレブアイテム — 誰もが読む1人のユーザー、1つの商品、1つのテナント。
  • カーディナリティの低いパーティションキーstatuscountrytype。 取りうる値が少ないと、すべての仕事をこなすパーティションも少なくなります。
  • 時刻でバケット化したキーPK = "2026-06-23"。今日の書き込みはすべて1つの パーティションを叩き、昨日のパーティションは永遠に冷たいままです。

SQL から来ると、これらはどれも問題になりません。人気の値に対する B-tree インデックスは 問題ないのです。DynamoDB では、人気の値 そのもの が物理配置の単位なので、人気が スループットの崖になります。

具体例: セレブのリーダーボード

グローバルなゲームのリーダーボードを運用しているとします。スコアは次のようにキー付けした テーブルに入っています。

PK = "BOARD#global"
SK = "PLAYER#<playerId>"

読み取りはスコア上位 N 件を取得し、書き込みは各試合後にプレイヤーの currentScore を 更新します。グローバルボードのすべての行が 1つの パーティションキー — BOARD#global — を共有するため、あらゆる読み取りと書き込みが単一のパーティションに当たります。

そこに、自分のランクの更新ボタンを連打する200万人のライブ視聴者を抱えた配信者を加えると、 その1つのパーティションは 3,000 読み取りユニットを超えます。テーブル内の他のあらゆる ボードが遊んでいる一方で、グローバルボードでは ProvisionedThroughputExceededException が返ってきます。

自爆装置は BOARD#global への集約です。1つの論理的なボードを、1つの物理的なキーとして モデル化してしまったのです。

書き込みを分散する: キーのシャーディング

対処は、カーディナリティを人為的に作り出すことです。パーティションキーに シャード サフィックス を付け、1つの論理ボードを N 個の物理パーティションにファンアウトさせます。

PK = "BOARD#global#<shard>"  -- shard = playerId mod 10
SK = "PLAYER#<playerId>"

書き込みは1つではなく10個のパーティションに散らばるようになりました — 書き込みの余裕が 10倍です。代償は、ボード全体の読み取りが10個すべてのシャードに当たってマージする必要が あることです。単一の Query はシャード境界をまたげないからです。読み取りの単純さを、 書き込みの分散と引き換えにするわけです。

自分で違いを確かめてみてください。下のビジュアライザに、同じキーを繰り返して貼り付けると、 すべての書き込みが1つのバケットに入ります — ホットパーティションです。シャードサフィックス (BOARD#global#0#9)を加えると、同じ書き込みが均等にファンアウトします。

パーティションキーの分布

1行に1つのパーティションキーの値を入力します。値を繰り返すとホットキーをシミュレートできます。

8 バケット8 キー
  • #0
    0
  • #1
    1
  • #2
    1
  • #3
    0
  • #4
    2
  • #5
    2
  • #6
    0
  • #7
    2

これは教育用に簡略化したハッシュであり、DynamoDB の実際の内部ハッシュではありません。DynamoDB は非公開の内部関数と、テーブルに応じて増えるパーティション数を使用します — 異なるキーがどう分散し、単一のホットキーがどう積み上がるかの直感を養う目的にのみ使用してください。

これは 直感のための教材用ハッシュであって、DynamoDB の実際の内部ハッシュではありません — 実際の関数とパーティション境界は AWS の内部実装です。これは「均等な分散 vs 偏り」として 読んでください。あるキーがどの物理パーティションに入るかの予測としてではありません。

AWS はこれを ライトシャーディング と呼び、高頻度でカーディナリティの低いキーにこそ これを推奨しています (AWS — ライトシャーディングの使用)。

これは シングルテーブル設計 の裏にあるのと同じ の発想です — データが「自然に」収まる形ではなく、 アクセスパターンに合わせてキーを形作るのです。

楽な部分はアダプティブキャパシティに任せる

DynamoDB には アダプティブキャパシティ が搭載されており、re:Invent 2018 のセッション 「Amazon DynamoDB Under the Hood」(DAT401) で取り上げられています。これはテーブルの スループットを、熱を帯びているパーティションへ継続的に再分配し、恒常的にホットなキーを 独自のパーティションへ隔離 します(キーレベルの隔離、 AWS — バースト&アダプティブキャパシティ)。

これは即時かつ無料です — ただし物理法則に縛られます (アダプティブキャパシティの仕組み)。アダプティブキャパシティは熱を キー で移動でき、熱による分割はホットなアイテムコレクションをソートキーの境界で 分割することさえできます。パーティションごとの上限が絶対的なまま残るのは、単一のホットな アイテム、単調増加するソートキー、または LSI を持つテーブル — セレブキーが依然として スロットルする場合 — に限られます。シャーディングは確定的な対処で、熱による分割は遅くて 機会依存的なので、それを当てにして待ってはいけません。

忙しいキーでスロットルが見えたときの判断経路は次のとおりです。

はいいいえ、多数のキーが同じプレフィックスはいいいえ1つのキーでスロットリング?単一アイテムがホットすぎる?キーをシャーディングまたは読み取りをキャッシュパーティションキーのカーディナリティが低い?プレフィックスを書き込みシャーディングアダプティブキャパシティが吸収する見込み

ほとんどのホットパーティションは「キーをシャーディングする」か「アダプティブキャパシティに 吸収させる」のどちらかに落ち着きます — この図は、単にどちらの枝にいるかを示すものです。

再設計の前に診断する

見えないものは直せません。スロットリングは、ProvisionedThroughputExceededException (プロビジョンド)として、あるいは ThrottledRequestsReadThrottleEvents/WriteThrottleEvents、そして ReadThrottleEventsForKeyRange/WriteThrottleEventsForKeyRange — パーティション上限に特化したカウント — として CloudWatch に現れます (AWS — CloudWatch メトリクス)。

それを CloudWatch Contributor Insights for DynamoDB と組み合わせましょう。最も アクセスの多いキーを直接ランク付けしてくれます — セレブキーを名前で確認する最速の方法です (AWS — Contributor Insights)。 そもそもホットキーが原因なのかまだ確信が持てないなら — DynamoDB は4つの異なる理由で スロットルします — まずは スロットリングのガイド から始めて、実際に当たった上限が どれなのかをメトリクスに語らせましょう。

シャーディングした読み取りパスをテストするときは、各シャードの KeyConditionExpression を手で組み立てることになります。それらをタイプミスなく生成するには DynamoDB Expression Builder を使ってください — シャードごとに正確な PK = :pk AND begins_with(SK, :sk) の形を出力します。

避けるべき落とし穴

  • 単調増加するソートキー。 単調なソートキー(タイムスタンプ、シーケンス番号)は、 すべての新規書き込みを1つのアイテムコレクションの同じ末尾に押し込み、熱による分割も 助けになりません — コレクションは 1,000 書き込みユニットに張り付いたままです。 ソートキーにエントロピーを加えるか、パーティションキーをシャーディングしましょう。
  • 読み取りが多いパスを不必要にシャーディングすること。 読み取りが支配的でアイテムが 小さいなら、キャッシュや、より分散したキーを持つ GSI のほうが、 シャーディングの散らばった読み取りコストに勝ることが多いです。
  • ホットパーティションと遅い Scan を混同すること。 Scan は何もかも読むから 遅く、ホットパーティションは1つのキーが過負荷だからスロットルします。別々の問題です — Query と Scan を参照してください。

次のステップ

シャーディングしたキーをスケッチし、実データに対して読み取りパスを検証しましょう。 DynamoDB Expression Builder でシャードごとの 条件を組み立て、DynoTable をダウンロード して自分のテーブルに対して実行し、 どのパーティションが実際に熱を帯びるかを見てください。

更新日