Azure Cosmos DB では、パーティション分割を使用してデータベース内のコンテナーをスケーリングし、アプリケーションのパフォーマンスニーズを満たします。 コンテナー内の項目は、論理パーティションと呼ばれる個別のサブセットに分割されます。 論理パーティションは、コンテナー内の各項目に関連付けられている パーティション キー の値に基づいて形成されます。 1 つの論理パーティション内のすべての項目で、パーティション キーの値は同じです。
たとえば、あるコンテナーに項目が保持されているとします。 各項目の UserID プロパティには一意の値があります。
UserID がそのコンテナー内の項目のパーティション キーであり、1,000 個の一意の UserID 値がある場合、1,000 個の論理パーティションがそのコンテナー内に作成されます。
コンテナー内の各項目には、その論理パーティションと、そのパーティション内で一意の項目 ID を決定するパーティション キーがあります。 パーティション キーと項目 ID を組み合わせて、項目のインデックスが作成されます。インデックスによって、項目が一意に識別されます。 パーティション キーを選択することは、アプリケーションのパフォーマンスに影響する重要な決定事項です。
この記事では、論理パーティションと物理パーティションの関係について説明し、パーティション分割のベスト プラクティスについて説明し、Azure Cosmos DB での水平スケーリングのしくみについて詳しく説明します。 パーティション キーを選択するためにこれらの内部の詳細を理解する必要はありませんが、この記事では、Azure Cosmos DB のしくみを明確にするために説明します。
論理パーティション
論理パーティションは、同じパーティション キーを共有する項目のセットです。 たとえば、食物の栄養に関するデータが含まれているコンテナーでは、すべてのアイテムに foodGroup プロパティが含まれています。 コンテナーのパーティション キーとして foodGroup を使用します。
foodGroup、Beef Products、Baked Products など、Sausages and Luncheon Meats に特定の値を持つアイテムのグループが、個別の論理パーティションを形成します。
論理パーティションでは、データベース トランザクションのスコープも定義します。 論理パーティション内のアイテムは、スナップショット分離が指定されたトランザクションを使用して更新することができます。 コンテナーに新しい項目が追加されると、新しい論理パーティションがシステムによって透過的に作成されます。 基になるデータを削除するときに、論理パーティションの削除について心配する必要はありません。
コンテナー内の論理パーティションの数に制限はありません。 各論理パーティションには、最大 20 GB のデータを格納できます。 有効なパーティション キーには、さまざまな値があります。 たとえば、すべてのアイテムに foodGroup プロパティが含まれているコンテナーでは、Beef Products 論理パーティション内のデータを最大 20 GB まで拡張できます。 可能性がある多様な値を格納できるパーティション キーを選択することで、コンテナーを確実にスケーリングできます。
Azure Monitor アラートを使用して、 論理パーティションのサイズが 20 GB に近づいているかどうかを監視します。
物理パーティション
コンテナーは、物理パーティション間でデータとスループットを分散することによってスケーリングされます。 内部的には、1 つ以上の論理パーティションが 1 つの物理パーティションにマップされます。 通常、小さいコンテナーには多くの論理パーティションがありますが、必要な物理パーティションは 1 つだけです。 論理パーティションとは異なり、物理パーティションは内部システム実装であり、Azure Cosmos DB によって完全に管理されます。
コンテナー内の物理パーティションの数は、次の特性によって異なります。
プロビジョニングされたスループットの量 (個々の物理パーティションからは、1 秒あたり最大 10,000 の要求ユニットのスループットを提供できます)。 物理パーティションに 10,000 RU/秒の制限がある場合、論理パーティションにも 10,000 RU/秒の制限があることを意味します。各論理パーティションは 1 つの物理パーティションにのみマップされるためです。
合計データ ストレージ (個々の物理パーティションには最大 50 ギガバイトのデータを格納できます)。
注意
物理パーティションは、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 が物理パーティションに対し、パーティション キー ハッシュのキー空間を均等に割り当てます。
ストアド プロシージャまたはトリガー内のトランザクションは、単一の論理パーティション内の項目に対してのみ許可されます。
レプリカ セット
各物理パーティションは、レプリカ セットとも呼ばれるレプリカの セットで構成されます。 各レプリカによって、データベース エンジンのインスタンスがホストされます。 レプリカ セットにより、物理パーティション内に格納されたデータの耐久性、高可用性、一貫性が確保されます。 物理パーティション内の各レプリカは、パーティションのストレージ クォータを継承します。 物理パーティションのすべてのレプリカは、その物理パーティションに割り当てられたスループットをまとめてサポートします。 レプリカ セットは Azure Cosmos DB によって自動的に管理されます。
通常、小さいコンテナーには 1 つの物理パーティションが必要ですが、少なくとも 4 つのレプリカが残っています。
この図は、論理パーティションがグローバルに分散された物理パーティションにどのようにマップされるかを示しています。 画像の [Partition set](パーティション セット) は、複数のリージョンにまたがって同じ論理パーティション キーを管理している物理パーティションのグループを表しています。
パーティション キーを選択する
パーティション キーには、パーティション キーのパスとパーティション キーの値の 2 つのコンポーネントがあります。 たとえば、項目 { "userId" : "Andrew", "worksFor": "Microsoft" } について考えてみましょう。"userId" をパーティション キーとして選んだ場合、次の 2 つのパーティション キー コンポーネントがあります。
パーティション キーのパス (例: "/userId")。 パーティション キーのパスには、英数字とアンダースコア (_) 文字を使用できます。 また、標準パス表記 (/) を使用して、入れ子になったオブジェクトを使用することもできます。
パーティション キーの値 (例:"Andrew")。 パーティション キーの値には、文字列型または数値型を使用できます。
スループット、ストレージ、パーティション キーの長さの制限については、 Azure Cosmos DB サービスのクォータ に関する記事を参照してください。
パーティション キーの選択はシンプルですが、Azure Cosmos DB での設計上の重要な選択です。 パーティション キーを選択すると、そのパーティション キーを適切に変更することはできません。 パーティション キーを変更する必要がある場合は、目的のパーティション キーを使用して新しいコンテナーにデータを移動します。 コンテナー コピー ジョブ は、このプロセスに役立ちます。 または、 グローバル セカンダリ インデックス (プレビュー) を追加して、特定のクエリ パターン用に最適化されたさまざまなパーティション キーを使用してデータのコピーを作成することもできます。
すべてのコンテナーに対して、パーティション キーは次の必要があります。
値が変更されないプロパティであること。 プロパティがパーティション キーの場合、そのプロパティの値を更新することはできません。
String値のみを含むか、Stringに従って倍精度数値の境界を超える可能性がある場合は、数値をに変換します。 Json 仕様では、相互運用性の問題が原因で、この境界外の数値を使用するのが不適切な方法である理由が説明されています。 これらの懸念事項は、パーティション キー列に特に関連します。これは不変であり、後でデータの移行を変更する必要があるためです。高いカーディナリティがあること。 言い換えると、プロパティには、有効な値が広範囲に及ぶことが必要です。
要求ユニット (RU) の消費量とデータ ストレージをすべての論理パーティションに均等に分散すること。 この分散により、物理パーティション全体でも RU の消費とストレージの分散が保証されます。
通常は 2048 バイト以下の値、または大きなパーティション キーが有効になっていない場合は 101 バイトの値があること。 詳細については、大きいパーティション キーに関する記事を参照してください。
Azure Cosmos DB で複数項目の ACID トランザクションが必要な場合は、ストアド プロシージャまたはトリガーを使用する必要があります。 すべての JavaScript ベースのストアド プロシージャとトリガーのスコープは、1 つの論理パーティションに限定されます。
注意
物理パーティションが 1 つしかない場合、すべてのクエリが同じ物理パーティションを対象としているため、パーティション キーの値が関係しない可能性があります。
パーティション キーの種類
| パーティション分割戦略 | いつ使用するか | 長所 | 短所 |
|---|---|---|---|
| 通常のパーティション キー (CustomerId、OrderId など) | パーティション キーのカーディナリティが高く、クエリ パターン (CustomerId によるフィルター処理など) に合わせて使用します。 クエリが主に 1 人の顧客のデータを対象とするワークロードに適しています (たとえば、顧客のすべての注文を取得する)。 | 管理が簡単です。 アクセス パターンがパーティション キーと一致する場合の効率的なクエリ (CustomerId によるすべての注文のクエリなど)。 アクセス パターンに一貫性がある場合は、クロスパーティション クエリを防止します。 | 一部の値 (トラフィックの多い顧客など) が他の値よりも多くのデータを生成する場合に、ホット パーティションが発生するリスク。 特定のキーのデータ ボリュームが急速に増加すると、論理パーティションあたり 20 GB の制限に達する可能性があります。 |
| 合成パーティション キー (CustomerId + OrderDate など) | カーディナリティが高く、クエリ パターンに一致するフィールドが 1 つもない場合に使用します。 データを物理パーティション間で均等に分散する必要がある書き込み負荷の高いワークロードに適しています (たとえば、同じ日付に多数の注文が行われます)。 | パーティション間でデータを均等に分散し、ホット パーティションを減らすのに役立ちます (CustomerId と OrderDate の両方による注文の分散など)。 複数のパーティションに書き込みを分散し、スループットを向上させます。 | 1 つのフィールドでのみフィルター処理するクエリ (CustomerId のみなど) では、パーティション間クエリが発生する可能性があります。 パーティション間クエリにより、RU 消費量が増加し (存在するすべての物理パーティションに対して 2 ~ 3 RU/秒の追加料金)、待機時間が増加する可能性があります。 |
| 階層パーティション キー (HPK) (CustomerId/OrderId、StoreId/ProductId など) | 大規模なデータセットをサポートするために複数レベルのパーティション分割が必要な場合に使用します。 クエリが階層の第 1 レベルと第 2 レベルでフィルター処理する場合に最適です。 | 複数のレベルのパーティション分割を作成することで、20 GB の制限を回避するのに役立ちます。 両方の階層レベルに対する効率的なクエリ (たとえば、最初に CustomerID でフィルター処理し、次に OrderID でフィルター処理するなど)。 最上位レベルを対象とするクエリ (たとえば、特定の CustomerID からすべてのデータを取得する) のクロスパーティション クエリを最小限に抑えます。 | 第 1 レベルのキーのカーディナリティが高く、ほとんどのクエリに含まれるように、慎重な計画が必要です。 通常のパーティション キーよりも管理が複雑です。 クエリが階層に合わない場合 (たとえば、CustomerID が第 1 レベルの場合は OrderID によるフィルター処理のみ)、クエリのパフォーマンスが低下する可能性があります。 |
| グローバル セカンダリ インデックス (GSI) - プレビュー (たとえば、ソースは CustomerId を使用し、GSI は OrderId を使用) | すべてのクエリ パターンで機能する 1 つのパーティション キーが見つからない場合に使用します。 複数の独立したプロパティで効率的にクエリを実行する必要があり、多数の物理パーティションを持つワークロードに最適です。 | GSI パーティション キーを使用する場合のクロスパーティション クエリを排除します。 ソース コンテナーからの自動同期を使用して、同じデータに対して複数のクエリ パターンを許可します。 ワークロード間のパフォーマンスの分離。 | 各 GSI には、追加のストレージと RU コストがあります。 GSI 内のデータは、最終的にはソース コンテナーと一致します。 |
読み取り負荷の高いコンテナーのパーティション キー
ほとんどのコンテナーでは、これらの条件は、パーティション キーを選択するときに考慮する必要があるすべてです。 ただし、大規模な読み取り負荷の高いコンテナーの場合は、クエリでフィルターとして頻繁に表示されるパーティション キーを選択することができます。 フィルター述語にパーティション キーを含めると、クエリを 関連する物理パーティションのみに効率的にルーティングできます。
このプロパティは、ワークロードの要求のほとんどがクエリであり、ほとんどのクエリで同じプロパティに対して等値フィルターを使用する場合に適したパーティション キーの選択です。 たとえば、UserID に対してフィルター処理を行うクエリを頻繁に実行する場合、パーティション キーとして UserID を選択するとクロスパーティション クエリの数が減少します。
コンテナーが小さい場合は、パーティション間クエリのパフォーマンスを心配するのに十分な物理パーティションがない可能性があります。 Azure Cosmos DB 内の小さなコンテナーのほとんどは、1 つまたは 2 つの物理パーティションのみを必要とします。
コンテナーがいくつかの物理パーティションに拡張される可能性がある場合は、クロスパーティション クエリを最小化するパーティション キーを選択する必要があります。 次のいずれかのシナリオに該当する場合、コンテナーには複数の物理パーティションが必要です。
コンテナーに 30,000 を超える要求ユニットがプロビジョニングされている
コンテナーが 100 GB を超えるデータを格納する
クロスパーティション クエリのグローバル セカンダリ インデックス
アプリケーションで複数の異なるプロパティを効率的に使用してデータのクエリを実行する必要がある場合、 グローバル セカンダリ インデックス (プレビュー) は、データセットに対して 1 つのパーティション キー戦略を使用する代わりに使用できます。 グローバル セカンダリ インデックスは、異なるパーティション キーを持つ追加のコンテナーであり、ソース コンテナーのデータと自動的に同期されます。
次の場合は、グローバル セカンダリ インデックスを検討してください。
- 1 つのパーティション キー戦略では満たされない複数のクエリ パターンがある
- 既存のパーティション キーを変更すると、中断が発生する
- 分析ワークロードまたは検索ワークロードをトランザクション操作から分離する必要がある
グローバル セカンダリ インデックスは、特定のクエリ パターン用に最適化された異なるパーティション キーを持つ同じデータを格納することで、クロスパーティション クエリを回避するのに役立ちます。 この方法では、パーティション キーの最適化だけでは不十分なシナリオでは、RU の消費量を大幅に削減し、クエリのパフォーマンスを向上させることができます。
パーティション キーとして項目 ID を使用する
注意
このセクションは、主に NoSQL 用 API に適用されます。 Gremlin 用 API などの他の API では、パーティション キーとしての一意識別子はサポートされていません。
コンテナーにさまざまな可能な値を持つプロパティがある場合は、パーティション キーを選択することをお勧めします。 このようなプロパティの例として、 項目 ID があります。 サイズが小さく読み取り負荷の高いコンテナー、または、あらゆるサイズの書き込みの多いコンテナーの場合、項目 ID (/id) は、必然的にパーティション キーに適しています。
システム プロパティ 項目 ID は、コンテナー内のすべての項目に存在します。 項目の論理 ID を表す他のプロパティがある場合があります。 多くの場合、これらの一意識別子は 、項目 ID と同じ理由で優れたパーティション キーの選択肢でもあります。
項目 ID は、次のような理由でパーティション キーの選択肢として適しています。
- 有効な値の範囲が幅広い (項目ごとに 1 つの一意の 項目 ID)。
- 項目ごとに一意の "項目 ID" があるため、"項目 ID" は、RU の消費量とデータ ストレージを均等に分散する上で非常に役立ちます。
- "項目 ID" がわかっている場合は、項目のパーティション キーが常にわかっているため、効率的なポイント読み取りを簡単に行うことができます。
パーティション キーとして 項目 ID を 選択する場合は、次の注意事項を考慮してください。
- 項目 ID がパーティション キーの場合、コンテナー全体の一意識別子になります。 重複する識別子を持つアイテムを作成することはできません。
- 多数の物理パーティションを含む読み取り負荷の高いコンテナーがある場合、"項目 ID" を持つ等値フィルターを使用するクエリの方が効率的になります。
- ストアド プロシージャまたはトリガーは、複数の論理パーティションを対象にすることはできません。