DynamoDB の物理パーティション
物理パーティションは、DynamoDB が実際にデータを格納する単位です。SSD の一切れで、 アベイラビリティゾーンをまたいでレプリケートされ、キー空間の一切れを保持します。テーブルは 論理的なものです。バイト——そしてスループットの上限——が本当に宿るのはパーティションです。
DynamoDB のパーティションはどう動きますか?
DynamoDB はテーブルを物理パーティションにまたがって格納します。アベイラビリティゾーンを またいでレプリケートされた SSD の一切れです。それぞれ約 10 GB、毎秒 3,000 読み取りユニット、 毎秒 1,000 書き込みユニットで頭打ちになります。の ハッシュがアイテムの落ちるパーティションを決め、DynamoDB はパーティションが成長したり ホットになったりすると自動的に分割します。
- すべてのパーティションは約 10 GB のストレージ、毎秒 3,000 読み取りユニット、毎秒 1,000 書き込みユニットで頭打ちになる。 これらの上限はテーブルごとではなくパーティションごとです。
- のハッシュがパーティションを選ぶ。 同じキーを 持つアイテムは一緒に落ちます。単一のホットな——あるいは 単調増加するソートキー——が1つのパーティションを釘付けにするものです。
- DynamoDB はあなたの代わりにパーティションを分割する——サイズで、そして持続する熱で—— 1つのキーのアイテムコレクションをソートキーの境界で分割することも含みます。ただし LSI か 増え続けるソートキーがそれを妨げる場合を除きます。
- キャパシティに余裕があるのにスロットリングするのが手がかり。 テーブルが 5% の使用率
なのに
ProvisionedThroughputExceededエラーが出るなら、単一のパーティションが上限に 達しています。
アイテムがパーティションを見つける仕方
DynamoDB は、パーティションキーの値を内部のハッシュ関数に通します。ハッシュの出力が物理 パーティションを選びます。同じキーを入れれば、同じパーティションが出てきます——毎回。
SQL から来ると、類似物はありません。チューニングするインデックスの B ツリーもなく、手で 割り当てるシャードキーもありません。配置は、あなたが制御せず、決して目にしないハッシュです。
パーティションキーを共有するアイテムはを
形成し、一緒に格納され、ソートキーでソートされます。それこそが、1つのキーへの Query を
安くするものです——1つのパーティション上の連続した1続きを読むのです。(Query vs Scan
を参照。)
ゲームの試合イベントストアを取り上げます。テーブルのキーは arenaId (パーティション) と
eventKey (ソート) です。
# Item
arenaId = "ARENA#7f3a"
eventKey = "EVT#1719100800#a91c"
playerTag = "Nightjar"
dmgDealt = 412
アリーナ 7f3a のすべてのイベントは同じパーティションにハッシュされ、ソートキー順に
積み重なります。「この試合のタイムラインを読む」には最高です。その1つのアリーナが
すべてのトラフィックを集めるなら、それは負債です。
すべてのパーティションが強制する3つの上限
単一のパーティションは、最大でも以下を提供するように設計されています。
| 上限 | パーティションあたり | 数え方 |
|---|---|---|
| ストレージ | 約 10 GB | 生のアイテムのバイト |
| 読み取りキャパシティ | 毎秒 3,000 読み取りユニット | 1 RU = 1回の 4 KB の強い整合性のある読み取り |
| 書き込みキャパシティ | 毎秒 1,000 書き込みユニット | 1 WU = 1回の 1 KB の書き込み |
出典:AWS の パーティションキーを設計するためのベストプラクティス ガイド。
アイテムサイズが計算をスケールさせます。20 KB のアイテムは強い整合性のある読み取り1回に つき 5 読み取りユニットかかるので、1つのパーティションはスロットリングする前に毎秒約 600 回 そうした読み取りを提供します——3,000 ではありません。書き込みコストは 1 KB ごとに、読み取り コストは 4 KB ごとに切り上げます。
罠:これらは_パーティション_の上限であって、_テーブル_の上限ではありません。テーブルが 40,000 WCU にプロビジョンドされていても、すべての書き込みが 1,000 で頭打ちになる1つの パーティションを叩いていれば、スロットリングし得ます。
パーティションが分割される仕方
DynamoDB は2つの場合に自動的にパーティションを追加します。あなたがコマンドを実行することは 決してありません。
サイズによる分割。 パーティションが約 10 GB に向かって埋まると、DynamoDB はそのキー 範囲を2つに分割し、アイテムの半分を新しいパーティションに移します。ストレージは透過的に 成長し、その間ずっと読み取りと書き込みは動き続けます。
熱による分割。 パーティションがスループットの上限近くの持続的なトラフィックを受けると、 DynamoDB はホットなキー範囲を分割し、各半分が自分のパーティションに落ちるようにします。 AWS はこれをsplit-for-heat の仕組みと呼びます。自ずと止まる短いスロットリングの バーストは、しばしば split-for-heat が作動したことを意味します——ただし短いスパイクは 単にバーストキャパシティが枯れただけのこともあります。
分割は多くのキーにまたがって余地を稼ぎ、split-for-heat は1つのキーのアイテムコレクション をソートキーの切れ目で切り分けることさえできます。それが広げられないのは、単一のホット アイテム、増え続けるソートキー、あるいは LSI に釘付けにされたコレクションです。
ホットキーが分割器に勝つ理由
ここが落とし穴です。分割はパーティションキーの_範囲_を再分配します。トラフィックが1つの キーの値に集中すると、すべてのリクエストが同じパーティションにハッシュされ、分割すべき 範囲が残りません。
アリーナ 7f3a がトーナメントの決勝で毎秒 4,000 書き込みを引く一方、他のすべての
アリーナがアイドルなら、1,000 でスロットリングします——そして split-for-heat はここでは
救えません。タイムスタンプがプレフィックスの eventKey が単調なので、新しい書き込みは
すべて1つの狭いソートキー範囲の先端に落ち、切り分けるものがないからです。より新しい
KeyRangeThroughputExceeded のスロットリング理由が、まさにこれを名指しします。テーブル
ではなく、1つのパーティションのキー範囲が上限を超えているのです。
修正はキャパシティのスライダーではなく、データモデルにあります。ホットキーを 書き込みシャーディングしましょう。小さなサフィックスを付け足して、1つの論理的な アリーナを N 個の物理パーティションに広げます。
arenaId = "ARENA#7f3a#3" # shard 0..9, chosen per write読み取りはそのときシャードにまたがって分散し、クライアント側でマージします。アプリケーション
コードの1行に触れる前に、各シャードのキーの形と Query を
DynamoDB 式ビルダーでプロトタイプできます。
1つのニュアンス:LSI の例外
ストレージがパーティションキーごとに_確かに_上限されるケースが1つあります。がなければ、アイテムコレクションは、格納バイトとスループットの 両方を提供するために必要なだけ多くのパーティションにまたがって分割されます——数十億の ソートキーの値でも問題ありません。
LSI を追加すると、1つのパーティションキーのコレクション全体が単一の 10 GB パーティション に収まらなければなりません。LSI がそれを共有するからです。それが GSI vs LSI で扱う PK ごとの崖であり——ほとんどのチームが GSI に手を伸ばすもう1つの理由です。
パーティションを冷たく保つ設計
あなたが実際に制御できるてこは、パーティションキーです。行数に対して多くの別々の値を 持つものを選び、トラフィックが均等に広がるようにしましょう。(さらなるパターンは シングルテーブル設計に。)
- 高カーディナリティのキー。 ユーザーごと、テナントごとのキーは、みなが一斉に叩く 日ごと、ステータスごとのキーに勝ります。
- 既知のホットキーに注意。 「現在のトーナメント」や「今日」の値は、出荷後ではなく前に、 集中のリスクです。
- 避けられないホットキーをシャーディングする。 1つのキーが並外れたトラフィックを 取らざるを得ないとき、サフィックスが標準の逃げ道です。
キャパシティに余裕があるのにスロットリングするのは、1つのパーティションがホットである という合図です。偏ったアイテムコレクションを調べ、シャーディングしたキーのレイアウトを DynoTableで予行演習しましょう——自分のテーブルに向け、SQL Workbench で パーティションキーを GROUP BY してどのキーが支配的かを見て、ページャーに呼び出される前に 修正をモデル化しましょう。