Azure Cosmos DB でのパーティション分割と水平スケーリング
適用対象: NoSQL MongoDB Cassandra Gremlin Table
Azure Cosmos DB では、パーティション分割を使用して、データベースの個別のコンテナーをスケーリングし、アプリケーションのパフォーマンスのニーズを満たします。 コンテナー内の項目は、論理パーティションと呼ばれる個別のサブセットに分割されます。 論理パーティションは、コンテナー内の各項目に関連付けられている "パーティション キー" の値に基づいて形成されます。 1 つの論理パーティション内のすべての項目で、パーティション キーの値は同じです。
たとえば、あるコンテナーに項目が保持されているとします。 各項目の UserID
プロパティには一意の値があります。 UserID
がそのコンテナー内の項目のパーティション キーであり、1,000 個の一意の UserID
値がある場合、1,000 個の論理パーティションがそのコンテナー内に作成されます。
項目の論理パーティションを決めるパーティション キーに加えて、コンテナー内の各項目には "項目 ID" (論理パーティション内で一意) があります。 パーティション キーと項目 ID を組み合わせて、項目のインデックスが作成されます。インデックスによって、項目が一意に識別されます。 パーティション キーを選択することは、アプリケーションのパフォーマンスに影響する重要な決定事項です。
この記事では、論理パーティションと物理パーティションの関係について説明します。 さらに、パーティション分割のベスト プラクティスと、Azure Cosmos DB での水平方向のスケーリングのしくみについて詳しく説明します。 これらの内部的な詳細について、Azure Cosmos DB のしくみを明確にするために説明していますが、パーティション キーを選択するために理解しておく必要はありません。
論理パーティション
論理パーティションは、同じパーティション キーを持つ一連のアイテムで構成されます。 たとえば、食物の栄養に関するデータが含まれているコンテナーでは、すべてのアイテムに foodGroup
プロパティが含まれています。 このコンテナーのパーティション キーとして foodGroup
プロパティを使用できます。 Beef Products
、Baked Products
、Sausages and Luncheon Meats
など、foodGroup
に特定の値を持つアイテムのグループが、個別の論理パーティションを形成します。
論理パーティションでは、データベース トランザクションのスコープも定義します。 論理パーティション内のアイテムは、スナップショット分離が指定されたトランザクションを使用して更新することができます。 コンテナーに新しい項目が追加されると、新しい論理パーティションがシステムによって透過的に作成されます。 基になるデータを削除するときに、論理パーティションの削除について心配する必要はありません。
コンテナー内の論理パーティションの数に制限はありません。 各論理パーティションには、最大 20 GB のデータを格納できます。 適切なパーティション キーを選択すると、可能性がある多様な値を格納できます。 たとえば、すべてのアイテムに foodGroup
プロパティが含まれているコンテナーでは、Beef Products
論理パーティション内のデータを最大 20 GB まで拡張できます。 可能性がある多様な値を格納できるパーティション キーを選択することで、コンテナーを確実にスケーリングできます。
Azure Monitor アラートを使用して、論理パーティションのサイズが 20 GB に近づいているかどうかを監視できます。
物理パーティション
コンテナーは、物理パーティション間でデータとスループットを分散することでスケーリングされます。 内部的には、1 つまたは複数の論理パーティションが単一の物理パーティションにマップされます。 小さなコンテナーには通常、多くの論理パーティションがありますが、必要なのは 1 つの物理パーティションのみです。 論理パーティションとは異なり、物理パーティションはシステムの内部実装であり、Azure Cosmos DB によって完全に管理されます。
コンテナー内の物理パーティションの数は、次の特性によって決まります。
プロビジョニングされたスループットの量 (個々の物理パーティションからは、1 秒あたり最大 10,000 の要求ユニットのスループットを提供できます)。 物理パーティションに 10,000 RU/秒の制限がある場合、論理パーティションにも 10,000 RU/秒の制限があることを意味します。各論理パーティションは 1 つの物理パーティションにのみマップされるためです。
データ ストレージの合計 (個々の物理パーティションには、最大 50 GB のデータを格納できます)。
注意
物理パーティションはシステムの内部実装であり、完全に Azure Cosmos DB によって管理されます。 物理パーティションは制御できないため、ソリューションを開発するときは物理パーティションには重点を置かないでください。 代わりに、パーティション キーに重点を置いてください。 論理パーティション間でスループットの消費が均等に分散されるパーティション キーを選択すると、物理パーティション間でのスループットが確実に均等に消費されます。
コンテナー内の物理パーティションの合計数に制限はありません。 プロビジョニングされたスループットまたはデータ サイズが増加すると、Azure Cosmos DB によって既存のパーティションが分割され、新しい物理パーティションが自動的に作成されます。 物理パーティションの分割がアプリケーションの可用性に影響を与えることはありません。 物理パーティションが分割された後も、単一の論理パーティション内のすべてのデータは同じ物理パーティションに格納されます。 物理パーティションの分割では、物理パーティションに対する論理パーティションの新しいマッピングが作成されるだけです。
コンテナーに対してプロビジョニングされたスループットは、物理パーティション間で均等に分割されます。 要求を均等に分散しないパーティション キーの設計では、"ホット" になるパーティションの小さなサブセットに送信される要求の数が多すぎる可能性があります。ホット パーティションは、プロビジョニングされたスループットの非効率的な使用につながります。これにより、レート制限が発生し、コストが高くなります。
たとえば、パーティション キーとして指定されたパス /foodGroup
を持つコンテナーを考えてみましょう。 コンテナーには任意の数の物理パーティションを含めることができますが、この例では 3 つとします。 1 つの物理パーティションには複数のパーティション キーを含めることができます。 例として、最も大きい物理パーティションには、上位 3 つの最も大きいサイズの論理パーティション (Beef Products
、Vegetable and Vegetable Products
、Soups, Sauces, and Gravies
) が含まれているとします。
1 秒あたり 18,000 要求ユニット (RU/秒) のスループットを割り当てた場合、3 つの物理パーティションではそれぞれ、プロビジョニングされたスループットの合計の 3 分の 1 を利用できます。 選択されている物理パーティション内では、論理パーティション キー (Beef Products
、Vegetable and Vegetable Products
、および Soups, Sauces, and Gravies
) は、物理パーティションにプロビジョニングされた 6,000 RU/秒を共同で利用できます。 プロビジョニングされたスループットはコンテナーの物理パーティション全体に均等に分割されるため、スループットの消費が均等に分散されるパーティション キーを選択することが重要です。 詳細については、適切な論理パーティション キーの選択に関するセクションを参照してください。
論理パーティションの管理
Azure Cosmos DB では、論理パーティションの物理パーティションへの配置が透過的かつ自動的に管理され、コンテナーのスケーラビリティとパフォーマンスのニーズが効率的に満たされます。 アプリケーションのスループットとストレージの要件が上がると、Azure Cosmos DB は論理パーティションを移動し、より多くの物理パーティションに負荷を自動的に分散します。 物理パーティションの詳細を参照できます。
Azure Cosmos DB は、ハッシュベースのパーティション分割を使用して、論理パーティションを物理パーティションに分散します。 Azure Cosmos DB では、項目のパーティション キー値をハッシュします。 ハッシュの結果で、論理パーティションが決定されます。 次に、Azure Cosmos DB が物理パーティションに対し、パーティション キー ハッシュのキー空間を均等に割り当てます。
ストアド プロシージャまたはトリガー内のトランザクションは、1 つの論理パーティション内の項目に対してのみ使用できます。
レプリカ セット
各物理パーティションは、一連のレプリカで構成されます ("レプリカ セット" とも呼ばれます)。 各レプリカによって、データベース エンジンのインスタンスがホストされます。 レプリカ セットにより、物理パーティション内に格納されたデータの耐久性、高可用性、一貫性が確保されます。 物理パーティションを構成する各レプリカは、そのパーティションのストレージ クォータを継承します。 物理パーティションのすべてのレプリカは、物理パーティションに割り当てられたスループットを一元的にサポートします。 レプリカ セットは Azure Cosmos DB によって自動的に管理されます。
小さなコンテナーは通常、1 つの物理パーティションのみを必要としますが、少なくとも 4 つのレプリカが保持されます。
次の画像は、世界中に分散する物理パーティションに対する論理パーティテョンのマッピングを表しています。 画像の [Partition set](パーティション セット) は、複数のリージョンにまたがって同じ論理パーティション キーを管理している物理パーティションのグループを表しています。
パーティション キーを選択する
パーティション キーには、パーティション キーのパスとパーティション キーの値の 2 つのコンポーネントがあります。 たとえば、項目 { "userId" : "Andrew", "worksFor": "Microsoft" }
について考えてみましょう。"userId" をパーティション キーとして選んだ場合、次の 2 つのパーティション キー コンポーネントがあります。
パーティション キーのパス (例: "/userId")。 パーティション キーのパスには、英数字とアンダースコア (_) 文字を使用できます。 また、標準パス表記 (/) を使用して、入れ子になったオブジェクトを使用することもできます。
パーティション キーの値 (例:"Andrew")。 パーティション キーの値には、文字列型または数値型を使用できます。
パーティション キーのスループット、ストレージ、および長さの制限については、記事「Azure Cosmos DB サービスのクォータ」を参照してください。
パーティション キーの選択はシンプルですが、Azure Cosmos DB での設計上の重要な選択です。 パーティション キーを選択した後は、その場で変更することはできません。 パーティション キーを変更する必要がある場合は、新しい必要なパーティション キーを使用して、新しいコンテナーにデータを移動する必要があります。 (コンテナー コピー ジョブは、このプロセスに役立ちます。)
すべてのコンテナーで、パーティション キーが次のようになっている必要があります。
値が変更されないプロパティであること。 プロパティがパーティション キーの場合、そのプロパティの値を更新することはできません。
String
値のみを含める必要があります。または、IEEE 754 binary64 に従って倍精度数値の境界外にある可能性がある場合は、数値をString
に変換するのが理想的です。 Json 仕様 では、一般的にこの境界の外で数値を使用することが相互運用性の問題が原因らしい不適切な方法である理由が示されています。 これらの問題は、パーティション キー列に特に関連します。これは不変であり、後で変更するにはデータ移行が必要であるためです。高いカーディナリティがあること。 言い換えると、プロパティには、有効な値が広範囲に及ぶことが必要です。
要求ユニット (RU) の消費量とデータ ストレージをすべての論理パーティションに均等に分散すること。 この分散により、物理パーティション全体でも RU の消費とストレージの分散が保証されます。
通常は 2048 バイト以下の値、または大きなパーティション キーが有効になっていない場合は 101 バイトの値があること。 詳細については、大きいパーティション キーに関する記事を参照してください。
Azure Cosmos DB で複数項目の ACID トランザクションが必要な場合は、ストアド プロシージャまたはトリガーを使用する必要があります。 すべての JavaScript ベースのストアド プロシージャとトリガーのスコープは、1 つの論理パーティションに限定されます。
注意
物理パーティションが 1 つだけの場合、すべてのクエリが同じ物理パーティションをターゲットにするため、パーティション キーの値には意味がないことがあります。
読み取り負荷の高いコンテナーのパーティション キー
ほとんどのコンテナーでは、パーティション キーを選択するときに考慮する必要があるのは、上記の条件だけです。 ただし、大規模な読み取り負荷の高いコンテナーの場合は、クエリでフィルターとして頻繁に表示されるパーティション キーを選択することができます。 フィルターの述語にパーティション キーを含めることで、クエリ呼び出しを関係する物理パーティションにだけ効率的にルーティングできます。
ワークロードの要求のほとんどがクエリで、ほとんどのクエリが同じプロパティに対する等値フィルターを適用している場合、このプロパティが適切なパーティション キーの選択になりえます。 たとえば、UserID
に対してフィルター処理を行うクエリを頻繁に実行する場合、パーティション キーとして UserID
を選択するとクロスパーティション クエリの数が減少します。
ただし、コンテナーが小さい場合は、恐らくクロスパーティション クエリのパフォーマンスについて心配するような量の物理パーティションがありません。 Azure Cosmos DB 内の小さなコンテナーのほとんどは、1 つまたは 2 つの物理パーティションのみを必要とします。
コンテナーがいくつかの物理パーティションに拡張される可能性がある場合は、クロスパーティション クエリを最小化するパーティション キーを選択する必要があります。 次のいずれかに該当する場合、コンテナーにはいくつかの物理パーティションが必要になります。
コンテナーは 30,000 RU を超えてプロビジョニングされる
コンテナーが 100 GB を超えるデータを格納する
パーティション キーとして項目 ID を使用する
Note
このセクションは、主に NoSQL 用 API に適用されます。 Gremlin 用 API など他の API では、パーティション キーとしての一意識別子はサポートされていません。
コンテナーに、有効な値が広範囲にわたるプロパティがある場合は、パーティション キーの選択肢として優れている可能性があります。 このようなプロパティの 1 つの例として、項目 ID があります。 サイズが小さく読み取り負荷の高いコンテナー、または、あらゆるサイズの書き込みの多いコンテナーの場合、項目 ID (/id
) は、必然的にパーティション キーに適しています。
"項目 ID" のシステム プロパティは、コンテナー内のすべての項目に存在します。 項目の論理 ID を表す他のプロパティがある場合があります。 多くの場合、これらの ID は "項目 ID" と同じ理由で、パーティション キーとして選択することに適しています。
項目 ID は、次のような理由でパーティション キーの選択肢として適しています。
- 有効な値の範囲が幅広い (項目ごとに 1 つの一意の 項目 ID)。
- 項目ごとに一意の "項目 ID" があるため、"項目 ID" は、RU の消費量とデータ ストレージを均等に分散する上で非常に役立ちます。
- "項目 ID" がわかっている場合は、項目のパーティション キーが常にわかっているため、効率的なポイント読み取りを簡単に行うことができます。
項目 ID をパーティション キーとして選択する場合は、次の点に注意してください。
- "項目 ID" がパーティション キーの場合は、コンテナー全体を通じての一意識別子になります。 重複する "項目 ID" を持つ項目を作成することはできません。
- 多数の物理パーティションを含む読み取り負荷の高いコンテナーがある場合、"項目 ID" を持つ等値フィルターを使用するクエリの方が効率的になります。
- 複数の論理パーティションを対象とするストアド プロシージャまたはトリガーを実行することはできません。