DynamoDB のパーティションキーの仕組み
パーティションキーは列ではありません — アドレスです。DynamoDB はそのキーをハッシュし、ハッシュがどの物理マシンにアイテムを格納するかを決めます。キーをうまく選べば負荷は分散し、まずく選べば1台のサーバーが熱を浴びます。
DynamoDB のパーティションキーはどのように機能するのか?
DynamoDB はパーティションキーを内部ハッシュ関数に通し、そのハッシュがどの物理パーティションにアイテムを格納するかを決めます。このキーは SQL の列のようにソートやインデックス化はされません — アドレスです。高カーディナリティのキーを選べば負荷は多くのパーティションに分散し、低カーディナリティのキーを選べば単一パーティションがすべての熱を受けます。
- キーはソートされず、ハッシュされる。 DynamoDB はパーティションキーを内部ハッシュに通してパーティションを選ぶ。隣り合う2つの値は、ディスク上では互いに遠く離れた場所に着地する。
- パーティションは本物のストレージユニット。 1つあたりおよそ 10 GB、毎秒 3,000 読み取りユニット、毎秒 1,000 書き込みユニットで頭打ちになる。あなたのトラフィックは、キーが分散するパーティションの数で割られる。
- ホットキーが地雷。 ほとんどのリクエストを1つのパーティションキー値に流し込むと、テーブルの残りがアイドルのまま、そのパーティションでスロットルされる。
- 高カーディナリティのキーが勝つ。 均等に当たる異なるキー値が多いほど、多くのパーティションが負荷を吸収する。
キーが実際に何をするかから始める
SQL から来ると、主キーは JOIN や ORDER BY に使う、ソートされインデックス化された列です。DynamoDB の パーティションキー(ハッシュキーとも呼ばれる)は別のことをします — それは 配置 を決めます。
DynamoDB はパーティションキーを内部ハッシュ関数に入れます。出力はキースペースにマップされ、キースペースは範囲に分割されます — 各範囲を 物理パーティション が所有します。そのパーティションは、本物のノード上の本物のストレージです。
つまりパーティションキーは1つの問いに答えます — どのマシンがこのアイテムを保持するか? ソートキー は、もしあれば、そのマシン 内 でアイテムを並べるだけです。配置には一切関与しません。
1回の書き込みをハッシュを通して追う
デバイスの読み取り値を取り込む SaaS を運用しているとします。テーブル SensorReadings はパーティションキー deviceId とソートキー readingTs を使います。deviceId = "vac-7741" の読み取り値を書き込みます。
その書き込みが辿る経路は次のとおりです — キーから、着地するディスクまで。
vac-7741 の書き込みはキースペース内の1点にハッシュされ、その点が P2 の範囲に入り、アイテムは P2 に着地します — そこで readingTs によって順序付けられます。
腑に落とすべきこと: "vac-7741" と "vac-7742" は1文字違いですが、それらのハッシュは無関係です。ほぼ確実に別々のパーティションに存在します。パーティションのキースペースに「近く」は存在しません。
これは DynamoDB が元の設計から受け継いだコンシステントハッシングの考え方です — 2007 年の Amazon Dynamo 論文("Dynamo: Amazon's Highly Available Key-value Store")は、単一ノードがボトルネックにならないよう、まさにハッシュによってキーをノードに分散させました。
パーティションの厳格な上限を尊重する
物理パーティションは有限です。AWS DynamoDB Developer Guide によると、1つあたりおよそ以下を保持します。
| 上限 | パーティションあたり |
|---|---|
| ストレージ | 約 10 GB |
| 読み取りスループット | 3,000 読み取りユニット/秒 |
| 書き込みスループット | 1,000 書き込みユニット/秒 |
パーティションが 10 GB を超えて埋まるとき、あるいはプロビジョンドスループットがより多くの余地を必要とするとき、DynamoDB はそれを 分割 します — キースペースの範囲が分割され、アイテムがより多くのパーティションに再分配されます。これは自動で、あなたがトリガーするものではありません。
落とし穴: 分割はアイテムを ハッシュ で広げます。すべてのホットなリクエストが単一のパーティションキー値を狙うなら、分割は助けになりません — そのトラフィックはすべて依然として同じ点にハッシュされます。単一キーの負荷をパーティションにまたいで分割することはできません。
罠に名前を付ける: ホットパーティション
ホットパーティション は古典的な地雷です。1つのパーティションキー値(またはごく少数の値)が、不釣り合いな割合のトラフィックを吸収するときに起こります。
具体的な失敗: SensorReadings を "us-east"、"eu-west" のような値を持つパーティションキー region に切り替えます。3つのリージョンは3つのキー値を意味し、つまり — 最大でも — 3つのパーティションが実働します。"us-east" を読み取りで叩けば、テーブルの総プロビジョンドキャパシティが未使用のまま、3,000 RCU でスロットルします。
DynamoDB の アダプティブキャパシティ はこれを和らげます — 未使用のスループットをビジーなパーティションへ移したり、極端にホットな単一キーを 隔離 して専用パーティションに乗せたりできます。AWS は re:Invent の "Advanced Design Patterns for DynamoDB" の深掘りセッションでこれを詳述しました。しかしアダプティブキャパシティは時間を稼ぐのであって、免疫を与えるのではありません — 個々の単一キーの負荷を細分化することはできません。分散を前提に設計し、安全網に寄りかからないこと。
高カーディナリティのキーを選ぶ
直し方は カーディナリティ です — 異なるキー値の数と、トラフィックがそれらにどれだけ均等に当たるか。
- 低カーディナリティ(
region、status、true/false): 少数のパーティション、トラフィックが集中、早くスロットルする。 - 高カーディナリティ(
deviceId、userId、注文 ID): 多くの値が多くのパーティションにハッシュされ、負荷が分散し、余裕が増す。
SQL から来ると status 列を喜んでインデックス化してフィルタするでしょう。DynamoDB の パーティション キーとしてそれは罠です — 分散できません。低カーディナリティの属性はフィルタとして、またはセカンダリインデックスのソートキーとして保ち、決して配置を決めるものにしないこと。
本来良いキーでも依然として偏るとき — 一握りの巨大テナントが残りを上回るとき — サフィックスを追加 して、1つの論理値を N パーティションにファンアウトします。たとえばシャーディングした書き込み経路の tenantId#3 です。読み取り時に再集約します。
キーが分散したら、パーティション 内 のアイテムを狙うには、ソートキーへの KeyConditionExpression を書きます。コードに組み込む前に、自分のスキーマに対してDynamoDB 式ビルダーで組み立てられます。
deviceId = "vac-7741" AND readingTs BETWEEN "2026-06-01" AND "2026-06-30"
これは単一パーティションから1台のデバイスの6月の窓を読みます — Scan ではなく Query です。パーティションキーがマシンを固定し、ソートキー条件が行を絞ります。
落とし穴と次のステップ
- SQL で読みやすいかでキーを選ばない。 分散する かで選ぶ。カーディナリティが先、クエリの便利さは後。
- テーブルの総キャパシティがキーごとに使えると思い込まない。 スループットはパーティション単位だ。テーブルがアイドルに見えても、1つのホット値がスロットルしうる。
- 分割と戦わない。 それは自動でハッシュ駆動だ — あなたの仕事は、分散するのに十分な異なるキーを与えることだ。
キーがきれいに分散したら、次の決定はパーティション内でアイテムをどうレイアウトするか — シングルテーブル設計を参照 — と、2つ目のアクセスパターンにセカンダリインデックスが正しいツールになるのはいつか、です。
DynoTable をダウンロードして実際のパーティションとキー分散を閲覧し、ホットキーがあなたをポケットベルで起こす前に見つけ出しましょう。