こんにちは。アプリケーションサービス本部ディベロップメントサービス2課の濱田です。
アイスコーヒーの美味しい時期になりましたね🧊
さて、本記事では DynamoDB の設計時に浮上する、パーティションキーについての疑問 を検討します。
「パーティションキーには連番は避け、ランダムな値(UUID等)を設定するべきか?」という疑問に対する回答を整理してお伝えします。
どなたかのお役に立てば幸いです!
結論:連番自体に問題はない
まず結論から申し上げると、答えは次のようなものになります。
パーティションキーが連番であること自体に問題はないが、そのことによって特定のパーティションにアクセスパターンが偏る場合は避けるべき。
つまり、連番かどうかよりも、アクセスパターンが偏るかどうか が重要なポイントです。
パーティションキーの仕組みを理解する
「パーティションキー」という名前にご注意
パーティションキー……「パーティション」のキー。
この名前は、物理的なパーティション(ディスク領域)を指定するキーである、という印象を誘います。
そこで、たとえば1、2、3というキーを指定してアイテムを保存した場合、物理的に近いパーティションにアイテムが保存されるような気がします。
もしこのような設計ならば、もちろんパーティションキーはランダムに設定するべきでしょう。
実際の仕組み:ハッシュ関数による分散
しかし実際には、1、2、3といった連番のキーを指定した場合にも、保存されるディスクは分散されます。
というのも、パーティションキーは直接パーティションを指定するものではなく、パーティションを決定するハッシュ関数への入力として用いられるもの だからです。
その根拠として以下のドキュメントの「データ分散: パーティションキー」の項目が挙げられます。
DynamoDB は項目をテーブルに書き込むため、パーティションキーバリューを内部ハッシュ関数への入力として使用します。ハッシュ関数からの出力値によって、項目が保存されるパーティションが決まります。 *1
またこれはあくまで傍証的な情報にはなりますが、より直接的に私たちの知りたいことを述べているのが、AWSでDynamoDBの技術者を担当していたと思しきDavid Yanacek氏のStackOverflowの発言です。
(2014年の投稿ですが、現在もDynamoDBの基礎的な構造は変わっていないでしょう)
タイトルも直球で、「DynamoDBのUUIDハッシュキー(=昔のパーティションキーの呼び名)は連番よりもいいのか?」といったものですね。
Yanacek氏の回答は以下のとおり。
"100444" and "100445" are not any more likely to be in the same partition than a completely different number, like "12345" for example. Think of a DynamoDB table as a big hash table, where the hash key of the table is the key into the hash table. The underlying hash table is organized by the hash of the key, not by the key itself.
邦訳すると——
「100444」と「100445」が同じパーティションに格納される可能性は、例えば「12345」のような全く異なる数値と比べて、特に高いわけではありません。DynamoDBのテーブルは、巨大なハッシュテーブルだと考えてください。テーブルのハッシュキー(訳註:パーティションキーの旧来の呼称)が、そのハッシュテーブルへのキーとなります。その内部のハッシュテーブルは、キーそのものではなく、キーのハッシュ値によって構成されています。
つまり、連番であろうとバラであろうと、ハッシュ関数によって適切に分散される ということですね。
(こう考えると「パーティションキー」という呼び方自体が少しミスリーディングで、リリース当初の「ハッシュキー」という呼び方の方が良さそうな気もします)
連番を避けるべき(とされる)理由を検証
とはいえ、ネット上のブログや、パパッと引き出される生成AIの回答等では「連番は避けるべき」という結論に至る場合もあるようです。
その理由を整理してみましょう。
1. ホットパーティション問題?
アクセスが特定のパーティションに偏る場合、いわゆる「ホットパーティション」が発生する可能性があります。
ホットパーティションとは、アクセスが集中してしまう特定のパーティションのことを指します。
ホットパーティションがよくない直接的な理由は、ひとえに特定のパーティションに対するスロットリング(上限を超えたため利用が制限されること)にあります。
パーティションの読み込みおよび書き込みオペレーションは個別に管理されるため、単一のパーティションが 3,000 を超える読み込みオペレーションまたは 1,000 を超える書き込みオペレーションを受け取ると、スロットリングが発生します
また、日毎にホットパーティションが移行していく状況は「ローリングホットパーティション」と呼ばれています。
Beware that loading sequential data (where items have been sorted by the partition key making the load focus on one partition key at a time) creates a rolling hot partition.
邦訳すると——
シーケンシャルなデータをロードすると (項目がパーティションキーによってソートされ、ロードが一度に 1 つのパーティション キーに集中する)、ローリングホットパーティションが作成されることに注意してください。
ただ、「シーケンシャルなデータ」と「シーケンシャルなID」は別であることに気をつけましょう。
この問題は連番に限らず、アクセスパターンが偏る場合に発生する問題 なので、連番に限った話ではありません。
例えば、日毎にパーティションキーを00001, 00002 ...…と連番で作成し、そのキーの属性に日毎のニュースの記事の内容を保存していたとします。
ユーザーが最新のニュースを見る傾向がある場合、アクセスされるパーティションは常に最新のキーに集中することになります(これがローリングホットパーティションの問題です)。
一見連番が悪そうに見えるのですが、これは、数字が00001, 00002であることに起因する問題ではありません。
仮に二つの番号が31536と98271であったとしても、
1日目に31536(のハッシュ値)が指示するパーティションにアクセスが集中し、
2日目に98271(のハッシュ値)が指示するパーティションにアクセスが集中するという問題は解決しません。
1日ごとにホットパーティションが発生するという問題が結局解決されないのですね。
以上の例のように、時系列データで最新のデータにアクセスが集中する場合などがローリングホットパーティションの可能性につながるわけですが
これは設計上、アクセスパターンをうまく捌けていないという問題であり、連番そのものの問題ではないということです。
AWSドキュメント上でも、パーティションキーにアイテムの作成日を指定することは均一性の観点から悪い(bad)ものとされています。
2. アトミックカウンタの実装が必要?
パーティションキーに限らず、連番で値を設定する場合、ダブりや衝突なく、きちんと一つ一つの入力に対して連続的なIDを付与する仕組みが必要になります。
例えばですが、RDBではオートカウンタの機能がありますね。
他方でDynamoDBではカウンタを作らないといけない(ので、パーティションキーに連番を振るのは避けよう)……と考えたくもなるかもしれません。
確かにこの点を問題にする場合、「DynamoDBではパーティションキーをUUIDでランダムに設定した方が良い」という結論に至ることになりそうです。
ただし、カウンタの実装は、DynamoDBの Atomic Counters を利用すれば、アプリケーション上で実装可能です。
弊社ブログでもサンプルコードを提供しております。
従いまして、カウンタという要因は、DynamoDBだから連番を避けるべきだという決定的な理由にはならないように思います。
実際の判断基準
結局のところ、パーティションキーの設計で重要なのは以下の点です:
- アクセスパターンが均等に分散されるか(ホットパーティションにならないか)
- アプリケーションの要件に適しているか
連番であっても、これらの条件を満たしていれば問題ないように思います。
ただし、連番にするための仕組み(アトミックカウンタ)などの実装の手間も考慮すると、UUIDでなくわざわざ連番を採用するメリットがあるかを検討する必要はあるでしょう。
また逆に、UUIDを使っていても、アクセスパターンが偏れば同様の問題が発生する可能性があります。
やはり真の問題はアクセスパターンなのだと意識しておきたいです。
まとめ
本記事では、DynamoDBのパーティションキーに連番を使うべきかという疑問について検討してきました。
重要なポイントをまとめると:
- 連番自体に問題はない(ハッシュ関数により適切に分散される)
- アクセスパターンの偏りこそが真の問題
- 連番かUUIDかよりも、設計全体でのアクセス分散を考慮すべき
「連番は避けるべき」という直感に惑わされず、実際のアクセスパターンを考慮した設計を心がけたいです。
本記事は以上です。 みなさん、よき開発ライフを!
*1:なお、同ドキュメントには、パーティションキーが同一かつソートキーが異なるアイテムは、互いに近くまたソートが効いた状態になる(傾向がある)ことも示されています。以下引用です。
「テーブルに複合プライマリキー (パーティションキーとソートキー) がある場合、DynamoDB は データ分散: パーティションキー で説明したのと同じ方法でパーティションキーのハッシュ値を計算します。ただし、パーティションキーの値が同じ項目は互いに近く、ソートキー属性の値によってソートされた順序になる傾向があります」(強調は引用者)
濱田 明日郎(執筆記事の一覧)
アプリケーションサービス本部ディベロップメントサービス2課
ベルクソン哲学研究で博士号取得ののち、2024年にサーバーワークスに新卒入社。
2025 Japan All AWS Certifications Engineers
奄美大島出身。