다음을 통해 공유


Azure Cosmos DB의 계층적 파티션 키

적용 대상: NoSQL

Azure Cosmos DB는 수평적 크기 조정을 지원하기 위해 파티션 키를 기반으로 논리 파티션 및 물리 파티션에 데이터를 분산합니다. 계층적 파티션 키(하위 분할이라고도 함)를 사용하면 파티션 키에 대해 최대 세 개 수준의 계층 구조를 구성하여 데이터 배포를 더 최적화하고 더 높은 수준의 크기 조정을 구현할 수 있습니다.

현재 가상 키를 사용하거나 파티션 키가 20GB의 데이터를 초과할 수 있는 시나리오가 있는 경우 하위 분할이 도움이 될 수 있습니다. 이 기능을 사용하는 경우 논리 파티션 키 접두사는 초당 20GB 및 10,000RU/s(초당 요청 단위)를 초과할 수 있습니다. 접두사별 쿼리는 데이터를 보유하는 파티션의 하위 집합으로 효율적으로 라우팅됩니다.

계층적 파티션 키 선택

다중 테넌트 애플리케이션이 있는 경우 계층적 파티션 키를 사용하는 것이 좋습니다. 계층적 파티션을 사용하면 논리 파티션 키 제한인 20GB를 초과하여 크기를 조정할 수 있습니다. 현재 파티션 키 또는 단일 파티션 키가 자주 20GB에 도달하는 경우 계층적 파티션은 워크로드에 적합한 선택입니다.

계층적 파티션 키를 선택하는 경우 다음과 같은 일반적인 분할 개념을 염두에 두어야 합니다.

  • 모든 컨테이너의 경우 계층 파티션 키의 전체 경로(첫 번째 수준부터 시작)의 각 수준은 다음을 수행해야 합니다.

    • 높은 카디널리티를 갖습니다. 계층 파티션의 첫 번째, 두 번째 및 세 번째 키(해당하는 경우)에는 모두 가능한 광범위한 값이 있어야 합니다.
    • 모든 논리 파티션에 RU(요청 단위) 사용량과 데이터 스토리지를 균등하게 분산합니다. 이 분산을 통해 실제 파티션에서 균등한 RU 사용량과 스토리지 배포가 가능합니다.
  • 읽기가 많은 대규모 워크로드의 경우 쿼리에 자주 표시되는 계층적 파티션 키를 선택하는 것이 좋습니다. 예를 들어 다중 테넌트 애플리케이션에서 특정 사용자 세션을 필터링하기 위해 쿼리를 자주 실행하는 워크로드는 TenantId, UserIdSessionId의 계층적 파티션 키를 순서대로 활용할 수 있습니다. 필터 조건자에 파티션 키를 포함하여 쿼리를 관련 물리 파티션에만 효율적으로 라우팅할 수 있습니다. 읽기 작업이 많은 워크로드에 대한 파티션 키를 선택하는 방법에 대한 자세한 내용은 분할 개요를 참조하세요.

사용 사례

각 테넌트의 사용자에 대한 이벤트 정보를 저장하는 다중 테넌트 시나리오가 있다고 가정합니다. 이벤트 정보에는 로그인, 클릭스트림 또는 결제 이벤트를 포함하되 이에 국한되지 않는 이벤트 발생이 포함될 수 있습니다.

실제 시나리오에서 일부 테넌트는 수천 명의 사용자로 크게 확장할 수 있지만, 다른 많은 테넌트는 규모가 작고 사용자가 적습니다. /TenantId로 분할하면 단일 논리 파티션에서 Azure Cosmos DB 20GB 스토리지 제한을 초과할 수 있습니다. /UserId로 분할하면 테넌트 교차 파티션에 대한 모든 쿼리가 만들어집니다. 두 방법 모두에는 심각한 단점이 있습니다.

TenantIdUserId를 결합한 가상 파티션 키를 사용하면 애플리케이션이 복잡해집니다. 또한 모든 사용자를 미리 알고 지정하는 경우를 제외하고 한 테넌트에 대한 가상 파티션 키 쿼리는 여전히 파티션 간 쿼리입니다.

계층적 파티션 키를 사용하면 먼저 TenantId에서 분할한 다음, UserId에서 분할할 수 있습니다. TenantIdUserId 조합이 20GB를 초과하는 파티션을 생성할 것으로 예상되는 경우 SessionId와 같은 다른 수준으로 더 아래로 파티션을 분할할 수도 있습니다. 전체 깊이는 세 수준을 초과할 수 없습니다. 실제 파티션이 50GB의 스토리지를 초과하는 경우 Azure Cosmos DB는 실제 파티션을 자동으로 분할하여 데이터의 약 절반이 한 실제 파티션에 있고, 나머지 절반은 다른 실제 파티션에 있습니다. 사실상 하위 분할은 단일 TenantId 값에서 20GB의 데이터를 초과할 수 있으며, 이는 TenantId 데이터가 여러 실제 파티션에 걸쳐 있을 수 있음을 의미합니다.

TenantId 또는 TenantIdUserId 모두를 지정하는 쿼리는 관련 데이터가 포함된 실제 파티션의 하위 집합에만 효율적으로 라우팅됩니다. 전체 또는 접두사로 하위 분할된 파티션 키 경로를 지정하면 전체 팬아웃 쿼리를 효과적으로 방지할 수 있습니다. 예를 들어 컨테이너에 1,000개의 실제 파티션이 있지만 특정 TenantId 값이 5개의 실제 파티션에만 있는 경우 쿼리는 더 적은 수의 관련 실제 파티션으로 라우팅됩니다.

계층 구조에서 항목 ID 사용

컨테이너에 가능한 값의 범위가 큰 속성이 있는 경우 속성은 계층의 마지막 수준에 대한 훌륭한 파티션 키 선택일 수 있습니다. 이러한 유형의 속성 중 가능한 한 가지 예는 항목 ID입니다. 컨테이너의 모든 항목에 시스템 속성 항목 ID가 있습니다. 항목 ID를 다른 수준으로 추가하면 논리 파티션 키 제한인 20GB를 초과하여 크기를 조정할 수 있습니다. 첫 번째 수준 또는 키의 첫 번째 및 두 번째 수준에 대해 이 제한을 초과하여 크기 조정할 수 있습니다.

예를 들어 TenantIdUserId로 분할된 다중 테넌트 워크로드에 대한 컨테이너가 있을 수 있습니다. TenantIdUserId의 단일 조합이 20GB를 초과할 수 있는 경우 세 가지 수준의 키 및 높은 카디널리티를 가진 세 번째 키를 사용하여 분할하는 것이 좋습니다. 이 시나리오의 예로는 세 번째 수준 키가 기본적으로 높은 카디널리티를 갖는 GUID인 경우입니다. TenantId, UserId 및 GUID의 조합이 20GB를 초과할 가능성은 거의 없으므로 TenantIdUserId의 조합이 20GB를 초과하여 효과적으로 크기 조정될 수 있습니다.

항목 ID를 파티션 키로 사용하는 방법에 대한 자세한 내용은 분할 개요를 참조하세요.

시작하기

Important

계층적 파티션 키를 사용하는 컨테이너 작업은 다음 SDK 버전에서만 지원됩니다. 계층적 파티션 키를 사용하여 새 컨테이너를 만들고 데이터에 대한 CRUD(만들기, 읽기, 업데이트 및 삭제기) 또는 쿼리 작업을 수행하려면 지원되는 SDK를 사용해야 합니다. 현재 지원되지 않는 SDK 또는 커넥터를 사용하려면 커뮤니티 포럼에 요청을 제출하세요.

지원되는 각 SDK의 최신 미리 보기 버전을 찾습니다.

SDK 지원되는 버전 패키지 관리자 링크
.NET SDK v3 >= 3.33.0 https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.33.0/
Java SDK v4 >= 4.42.0 https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/cosmos/azure-cosmos/CHANGELOG.md#4420-2023-03-17/
JavaScript SDK v4 4.0.0 https://www.npmjs.com/package/@azure/cosmos/
Python SDK >= 4.6.0 https://pypi.org/project/azure-cosmos/4.6.0/

계층적 파티션 키를 사용하여 컨테이너 만들기

시작하려면 최대 3개 수준의 깊이까지 미리 정의된 하위 분할 키 경로 목록을 사용하여 새 컨테이너를 만듭니다.

다음 옵션 중 하나를 사용하여 새 컨테이너를 만들 수 있습니다.

  • Azure Portal
  • SDK
  • Azure Resource Manager 템플릿
  • Azure Cosmos DB 에뮬레이터

Azure Portal

컨테이너를 만들고 계층적 파티션 키를 지정하는 가장 간단한 방법은 Azure Portal을 사용하는 것입니다.

  1. Azure Portal에 로그인합니다.

  2. 기존 Azure Cosmos DB for NoSQL 계정 페이지로 이동합니다.

  3. 왼쪽 메뉴에서 Data Explorer를 선택합니다.

    Data Explorer 메뉴 옵션이 강조 표시된 새 Azure Cosmos DB for NoSQL 계정의 페이지를 보여 주는 스크린샷.

  4. Data Explorer에서 새 컨테이너 옵션을 선택합니다.

    Data Explorer 내 새 컨테이너 옵션을 보여 주는 스크린샷의.

  5. 새 컨테이너에서 파티션 키/TenantId를 입력합니다. 나머지 필드의 경우 시나리오와 일치하는 값을 입력합니다.

    참고 항목

    여기서는 /TenantId를 예제로 사용합니다. 자체 컨테이너에서 계층적 파티션 키를 구현할 때 첫 번째 수준에 대한 키를 지정할 수 있습니다.

  6. 계층적 파티션 키 추가를 두 번 선택합니다.

    새로운 계층적 파티션 키를 추가하는 단추를 보여 주는 스크린샷.

  7. 하위 분할의 두 번째 및 세 번째 계층에 대해 각각 /UserId/SessionId를 입력합니다.

    세 개의 계층적 파티션 키 목록를 보여 주는 스크린샷.

  8. 확인을 선택하여 컨테이너를 만듭니다.

SDK

SDK를 사용하여 새 컨테이너를 만드는 경우 최대 세 개 깊이 수준의 하위 분할 키 경로 목록을 정의합니다. 새 컨테이너의 속성을 구성할 때 하위 파티션 키 목록을 사용합니다.

// List of partition keys, in hierarchical order. You can have up to three levels of keys.
List<string> subpartitionKeyPaths = new List<string> { 
    "/TenantId",
    "/UserId",
    "/SessionId"
};

// Create a container properties object
ContainerProperties containerProperties = new ContainerProperties(
    id: "<container-name>",
    partitionKeyPaths: subpartitionKeyPaths
);

// Create a container that's subpartitioned by TenantId > UserId > SessionId
Container container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

Azure Resource Manager 템플릿

하위 분할된 컨테이너에 대한 Azure Resource Manager 템플릿은 표준 컨테이너와 거의 동일합니다. 유일한 주요 차이점은 properties/partitionKey 경로의 값입니다. Azure Cosmos DB 리소스에 대한 Azure Resource Manager 템플릿을 만드는 방법에 대한 자세한 내용은 Azure Cosmos DB에 대한 Azure Resource Manager 템플릿 참조를 참조하세요.

다음 표의 값을 사용하여 partitionKey 개체를 구성하여 하위 분할된 컨테이너를 만듭니다.

Path
paths 계층적 파티션 키 목록(최대 3개 깊이 수준)
kind MultiHash
version 2

파티션 키 정의 예제

예를 들어 TenantId>UserId>SessionId로 구성된 계층적 파티션 키가 있다고 가정합니다. partitionKey 개체는 paths 속성의 세 가지 값, 즉 MultiHashkind 값 및 2version 값을 모두 포함하도록 구성됩니다.

partitionKey: {
  paths: [
    '/TenantId'
    '/UserId'
    '/SessionId'
  ]
  kind: 'MultiHash'
  version: 2
}

partitionKey 개체에 대한 자세한 내용은 ContainerPartitionKey 사양을 참조하세요.

Azure Cosmos DB 에뮬레이터

하위 분할 기능은 Azure Cosmos DB용 로컬 에뮬레이터의 최신 버전을 사용하여 테스트할 수 있습니다. 에뮬레이터에서 하위 분할을 사용하도록 설정하려면 /EnablePreview 플래그를 사용하여 설치 디렉터리에서 에뮬레이터를 시작합니다.

.\CosmosDB.Emulator.exe /EnablePreview

Warning

에뮬레이터는 현재 모든 계층적 파티션 키 기능을 포털로 지원하지 않습니다. 에뮬레이터는 현재 다음을 지원하지 않습니다.

  • Data Explorer를 사용하여 계층적 파티션 키를 사용하여 컨테이너 만들기
  • Data Explorer를 사용하여 계층적 파티션 키를 사용하여 항목으로 이동 및 상호 작용

자세한 내용은 Azure Cosmos DB 에뮬레이터를 참조하세요.

SDK를 사용하여 계층적 파티션 키가 있는 컨테이너 작업

계층적 파티션 키가 포함된 컨테이너가 있는 경우 이전에 지정된 버전의 .NET 또는 Java SDK를 사용하여 해당 컨테이너에서 작업을 수행하고 쿼리를 실행합니다.

컨테이너에 항목 추가

새 항목을 계층적 파티션 키가 사용하도록 설정된 컨테이너에 추가하는 두 가지 옵션이 있습니다.

  • 자동 추출
  • 수동으로 경로 지정

자동 추출

파티션 키 값이 설정된 개체를 전달하면 SDK에서 자동으로 전체 파티션 키 경로를 추출할 수 있습니다.

// Create a new item
UserSession item = new UserSession()
{
    id = "f7da01b0-090b-41d2-8416-dacae09fbb4a",
    TenantId = "Microsoft",
    UserId = "8411f20f-be3e-416a-a3e7-dcd5a3c1f28b",
    SessionId = "0000-11-0000-1111"
};

// Pass in the object, and the SDK automatically extracts the full partition key path
ItemResponse<UserSession> createResponse = await container.CreateItemAsync(item);

수동으로 경로 지정

SDK의 PartitionKeyBuilder 클래스에서 이전에 정의된 계층적 파티션 키 경로에 대한 값을 생성할 수 있습니다. 이 클래스는 새 항목을 하위 분할이 사용하도록 설정된 컨테이너에 추가할 때 사용됩니다.

SDK에서 개체로부터 경로를 추출할 수 있는 경우에도 규모에 맞게 전체 파티션 키 경로를 지정하면 성능이 향상될 수 있습니다.

// Create a new item object
PaymentEvent item = new PaymentEvent()
{
    id = Guid.NewGuid().ToString(),
    TenantId = "Microsoft",
    UserId = "8411f20f-be3e-416a-a3e7-dcd5a3c1f28b",
    SessionId = "0000-11-0000-1111"
};

// Specify the full partition key path when creating the item
PartitionKey partitionKey = new PartitionKeyBuilder()
            .Add(item.TenantId)
            .Add(item.UserId)
            .Add(item.SessionId)
            .Build();

// Create the item in the container
ItemResponse<PaymentEvent> createResponse = await container.CreateItemAsync(item, partitionKey);

항목의 키/값 조회(포인트 읽기) 수행

키/값 조회(포인트 읽기)는 하위 분할되지 않은 컨테이너와 비슷한 방식으로 수행됩니다. 예를 들어 TenantId>UserId>SessionId로 구성된 계층적 파티션 키가 있다고 가정합니다. 항목의 고유 식별자는 GUID입니다. 고유 문서 트랜잭션 식별자 역할을 하는 문자열로 표시됩니다. 단일 항목에서 포인트 읽기를 수행하려면 항목의 id 속성과 경로의 세 가지 구성 요소를 모두 포함한 파티션 키의 전체 값을 전달합니다.

// Store the unique identifier
string id = "f7da01b0-090b-41d2-8416-dacae09fbb4a";

// Build the full partition key path
PartitionKey partitionKey = new PartitionKeyBuilder()
    .Add("Microsoft") //TenantId
    .Add("8411f20f-be3e-416a-a3e7-dcd5a3c1f28b") //UserId
    .Add("0000-11-0000-1111") //SessionId
    .Build();

// Perform a point read
ItemResponse<UserSession> readResponse = await container.ReadItemAsync<UserSession>(
    id,
    partitionKey
);

쿼리 실행

하위 분할된 컨테이너에서 쿼리를 실행하는 데 사용되는 SDK 코드는 하위 분할되지 않은 컨테이너에서 쿼리를 실행하는 것과 동일합니다.

쿼리에서 WHERE 필터 또는 키 계층 구조의 접두사에 있는 파티션 키의 모든 값을 지정하면 SDK에서 쿼리를 해당 실제 ​​파티션으로 자동으로 라우팅합니다. 계층 구조의 "중간"만 제공하는 쿼리는 파티션 간 쿼리입니다.

예를 들어 TenantId>UserId>SessionId로 구성된 계층적 파티션 키를 고려합니다. 쿼리 필터의 구성 요소는 쿼리가 단일 파티션 쿼리인지, 대상 파티션 간 쿼리인지 또는 팬아웃 쿼리인지를 결정합니다.

쿼리 라우팅
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' AND c.SessionId = '0000-11-0000-1111' 지정된 TenantId, UserIdSessionId 값에 대한 데이터가 포함된 단일 논리 및 실제 파티션으로 라우팅됩니다.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' 지정된 TenantIdUserId 값에 대한 데이터가 포함된 논리 및 실제 파티션의 대상 하위 집합으로만 라우팅됩니다. 이 쿼리는 테넌트의 특정 사용자에 대한 데이터를 반환하는 대상 파티션 간 쿼리입니다.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' 지정된 TenantId 값에 대한 데이터가 포함된 논리 및 실제 파티션의 대상 하위 집합으로만 라우팅됩니다. 이 쿼리는 테넌트의 모든 사용자에 대한 데이터를 반환하는 대상 파티션 간 쿼리입니다.
SELECT * FROM c WHERE c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' 모든 실제 파티션으로 라우팅되어 팬아웃 파티션 간 쿼리가 발생합니다.
SELECT * FROM c WHERE c.SessionId = '0000-11-0000-1111' 모든 실제 파티션으로 라우팅되어 팬아웃 파티션 간 쿼리가 발생합니다.

하위 분할된 컨테이너에 대한 단일 파티션 쿼리

다음은 모든 수준의 하위 분할을 포함하는 쿼리를 실행하여 쿼리를 단일 파티션 쿼리로 효과적으로 만드는 예제입니다.

// Define a single-partition query that specifies the full partition key path
QueryDefinition query = new QueryDefinition(
    "SELECT * FROM c WHERE c.TenantId = @tenant-id AND c.UserId = @user-id AND c.SessionId = @session-id")
    .WithParameter("@tenant-id", "Microsoft")
    .WithParameter("@user-id", "8411f20f-be3e-416a-a3e7-dcd5a3c1f28b")
    .WithParameter("@session-id", "0000-11-0000-1111");

// Retrieve an iterator for the result set
using FeedIterator<PaymentEvent> results = container.GetItemQueryIterator<PaymentEvent>(query);

while (results.HasMoreResults)
{
    FeedResponse<UserSession> resultsPage = await resultSet.ReadNextAsync();
    foreach(UserSession result in resultsPage)
    {
        // Process result
    }
}

하위 분할된 컨테이너에 대한 대상 다중 파티션 쿼리

다음은 하위 분할 수준의 하위 집합을 포함하는 쿼리의 예제로, 이 쿼리를 대상 다중 파티션 쿼리로 효과적으로 만듭니다.

// Define a targeted cross-partition query specifying prefix path[s]
QueryDefinition query = new QueryDefinition(
    "SELECT * FROM c WHERE c.TenantId = @tenant-id")
    .WithParameter("@tenant-id", "Microsoft")

// Retrieve an iterator for the result set
using FeedIterator<PaymentEvent> results = container.GetItemQueryIterator<PaymentEvent>(query);

while (results.HasMoreResults)
{
    FeedResponse<UserSession> resultsPage = await resultSet.ReadNextAsync();
    foreach(UserSession result in resultsPage)
    {
        // Process result
    }
}

제한 사항 및 알려진 문제

  • 계층적 파티션 키를 사용하는 컨테이너 작업은 .NET v3 SDK, Java v4 SDK 및 JavaScript SDK의 미리 보기 버전에서만 지원됩니다. 계층적 파티션 키가 있는 새 컨테이너를 만들고 데이터에 대한 CRUD 또는 쿼리 작업을 수행하려면 지원되는 SDK를 사용해야 합니다. Python을 포함한 다른 SDK에 대한 지원은 현재 사용할 수 없습니다.
  • 다양한 Azure Cosmos DB 커넥터(예: Azure Data Factory 사용)에는 제한 사항이 있습니다.
  • 계층적 파티션 키는 최대 세 개의 깊이 계층까지만 지정할 수 있습니다.
  • 계층적 파티션 키는 현재 새 컨테이너에서만 사용하도록 설정할 수 있습니다. 컨테이너를 만들 때 파티션 키 경로를 설정해야 하며 나중에 변경할 수 없습니다. 기존 컨테이너에서 계층적 파티션을 사용하려면 계층적 파티션 키가 설정된 새 컨테이너를 만들고 컨테이너 복사 작업을 사용하여 데이터를 이동합니다.
  • 계층적 파티션 키는 현재 API for NoSQL 계정에 대해서만 지원됩니다. API for MongoDB 및 Cassandra는 현재 지원되지 않습니다.
  • 계층적 파티션 키는 현재 권한 기능에서 지원되지 않습니다. 계층적 파티션 키 경로의 부분 접두사에는 권한을 할당할 수 없습니다. 권한은 전체 논리 파티션 키 경로에만 할당될 수 있습니다. 예를 들어, TenantId - >UserId로 분할한 경우 특정 값 TenantId에 대한 권한을 할당할 수 없습니다. 그러나 TenantId 및 ``UserId``` 값을 모두 할당하면 파티션 키에 대한 권한을 할당할 수 있습니다.

다음 단계