DocumentDB-파티셔닝

데이터베이스가 10GB 이상으로 커지기 시작하면 새 컬렉션을 만든 다음 더 많은 컬렉션에 데이터를 분산하거나 분할하여 간단히 확장 할 수 있습니다.

조만간 10GB 용량의 단일 컬렉션은 데이터베이스를 포함하기에 충분하지 않을 것입니다. 이제 10GB는 그다지 큰 숫자처럼 들리지 않을 수 있지만, 우리는 일반 텍스트 인 JSON 문서를 저장하고 있으며 인덱스에 대한 스토리지 오버 헤드를 고려하더라도 10GB에 많은 일반 텍스트 문서를 저장할 수 있습니다.

확장 성과 관련하여 스토리지가 유일한 문제는 아닙니다. 컬렉션에서 사용할 수있는 최대 처리량은 S3 컬렉션에서 얻을 수있는 초당 250 개의 요청 단위입니다. 따라서 더 높은 처리량이 필요한 경우 여러 컬렉션으로 분할하여 확장해야합니다. 스케일 아웃 파티셔닝이라고도합니다.horizontal partitioning.

Azure DocumentDB를 사용하여 데이터를 분할하는 데 사용할 수있는 많은 접근 방식이 있습니다. 다음은 가장 일반적인 전략입니다-

  • 스필 오버 파티셔닝
  • 범위 분할
  • 조회 분할
  • 해시 파티셔닝

스필 오버 파티셔닝

스필 오버 파티셔닝은 파티션 키가 없기 때문에 가장 간단한 전략입니다. 많은 것에 대해 확신이 없을 때 시작하는 것이 좋은 선택입니다. 단일 컬렉션 이상으로 확장해야하는지 또는 추가해야 할 컬렉션 수 또는 추가해야하는 속도를 모를 수도 있습니다.

  • 스필 오버 파티셔닝은 단일 컬렉션으로 시작되며 파티션 키가 없습니다.

  • 컬렉션은 10GB 한도에 가까워 질 때까지 점점 커지기 시작하고 더 커집니다.

  • 용량이 90 %에 도달하면 새 컬렉션으로 넘어 가서 새 문서에 사용하기 시작합니다.

  • 데이터베이스가 더 많은 수의 컬렉션으로 확장되면 파티션 키를 기반으로하는 전략으로 전환 할 수 있습니다.

  • 이 작업을 수행 할 때 마이그레이션하려는 전략에 따라 문서를 다른 컬렉션으로 이동하여 데이터 균형을 다시 조정해야합니다.

범위 분할

가장 일반적인 전략 중 하나는 범위 분할입니다. 이 접근 방식을 사용하면 문서의 파티션 키가 속할 수있는 값 범위를 결정하고 해당 범위에 해당하는 컬렉션으로 문서를 보냅니다.

  • 날짜는 정의 된 날짜 범위에 속하는 문서를 보관하기 위해 컬렉션을 만드는이 전략에서 매우 일반적으로 사용됩니다. 충분히 작은 범위를 정의 할 때 컬렉션이 10GB 제한을 초과하지 않을 것이라고 확신 할 수 있습니다. 예를 들어, 단일 컬렉션이 한 달 동안 문서를 합리적으로 처리 할 수있는 시나리오가있을 수 있습니다.

  • 또한 대부분의 사용자가 이번 달 또는 지난 달의 데이터 인 현재 데이터를 쿼리하지만 사용자는 훨씬 오래된 데이터를 거의 검색하지 않는 경우 일 수 있습니다. 따라서 6 월에 구매할 수있는 가장 비싼 컬렉션이며 얻을 수있는 최고의 처리량을 제공하는 S3 컬렉션으로 시작합니다.

  • 7 월에 7 월 데이터를 저장하기 위해 다른 S3 컬렉션을 구입하고 6 월 데이터를 저렴한 S2 컬렉션으로 축소합니다. 그런 다음 8 월에 또 다른 S3 컬렉션을 얻고 7 월은 S2로, 6 월은 S1로 줄입니다. 매월 현재 데이터를 높은 처리량에 사용할 수 있도록 유지하고 오래된 데이터는 낮은 처리량으로 사용할 수 있도록 유지합니다.

  • 쿼리가 파티션 키를 제공하는 한 쿼리해야하는 컬렉션 만 쿼리되며 스필 오버 파티셔닝에서 발생하는 것처럼 데이터베이스의 모든 컬렉션이 쿼리되지 않습니다.

조회 분할

조회 파티셔닝을 사용하면 파티션 키를 기반으로 문서를 특정 컬렉션으로 라우팅하는 파티션 맵을 정의 할 수 있습니다. 예를 들어 지역별로 분할 할 수 있습니다.

  • 모든 미국 문서를 한 컬렉션에 저장하고, 모든 유럽 문서를 다른 컬렉션에 저장하고, 다른 지역의 모든 문서를 세 번째 컬렉션에 저장합니다.

  • 이 파티션 맵과 조회 파티션 해결 프로그램을 사용하면 각 문서에 포함 된 영역 속성 인 파티션 키를 기반으로 문서를 만들 컬렉션과 쿼리 할 컬렉션을 파악할 수 있습니다.

해시 파티셔닝

해시 파티셔닝에서 파티션은 해시 함수의 값에 따라 할당되므로 여러 파티션에 요청과 데이터를 균등하게 분산 할 수 있습니다.

이것은 일반적으로 많은 개별 클라이언트에서 생성되거나 소비되는 데이터를 분할하는 데 사용되며 사용자 프로필, 카탈로그 항목 등을 저장하는 데 유용합니다.

.NET SDK에서 제공하는 RangePartitionResolver를 사용한 범위 분할의 간단한 예를 살펴 보겠습니다.

Step 1− 새 DocumentClient를 만들고 CreateCollections 작업에서 두 ​​개의 컬렉션을 생성합니다. 하나는 A-M으로 시작하는 사용자 ID를 가진 사용자에 대한 문서를 포함하고 다른 하나는 사용자 ID N-Z에 대한 문서를 포함합니다.

private static async Task CreateCollections(DocumentClient client) {
   await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
      Id = “CollectionAM” }); 
		
   await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
      Id = “CollectionNZ” }); 
}

Step 2 − 데이터베이스에 대한 범위 분석기를 등록합니다.

Step 3− 파티션 키의 데이터 유형 인 새로운 RangePartitionResolver <string>을 생성합니다. 생성자는 두 개의 매개 변수, 파티션 키의 속성 이름과 리졸버에 대해 미리 정의하는 범위 및 해당 컬렉션의 목록 인 샤드 맵 또는 파티션 맵인 사전을 사용합니다.

private static void RegisterRangeResolver(DocumentClient client) {

   //Note: \uffff is the largest UTF8 value, so M\ufff includes all strings that start with M.
		
   var resolver = new RangePartitionResolver<string>(
      "userId", new Dictionary<Range<string>, string>() {
      { new Range<string>("A", "M\uffff"), "dbs/myfirstdb/colls/CollectionAM" },
      { new Range<string>("N", "Z\uffff"), "dbs/myfirstdb/colls/CollectionNZ" },
   });
	
   client.PartitionResolvers["dbs/myfirstdb"] = resolver;
 }

여기서 가능한 가장 큰 UTF-8 값을 인코딩해야합니다. 그렇지 않으면 첫 번째 범위는 하나의 단일 M을 제외한 어떤 M에서도 일치하지 않으며 두 번째 범위의 Z에서도 마찬가지입니다. 따라서 여기에서 인코딩 된 값을 파티션 키와 일치하는 와일드 카드로 생각할 수 있습니다.

Step 4− 리졸버를 생성 한 후 현재 DocumentClient로 데이터베이스에 등록합니다. 그렇게하려면 PartitionResolver의 사전 속성에 할당하기 만하면됩니다.

평소처럼 컬렉션이 아닌 데이터베이스에 대한 문서를 만들고 쿼리합니다. 해석기는이 맵을 사용하여 요청을 적절한 컬렉션으로 라우팅합니다.

이제 몇 가지 문서를 만들어 보겠습니다. 먼저 userId Kirk에 대해 하나를 생성 한 다음 Spock에 대해 하나를 생성합니다.

private static async Task CreateDocumentsAcrossPartitions(DocumentClient client) { 
   Console.WriteLine(); 
   Console.WriteLine("**** Create Documents Across Partitions ****");
	
   var kirkDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
      "Kirk", title = "Captain" }); 
   Console.WriteLine("Document 1: {0}", kirkDocument.Resource.SelfLink);
	
   var spockDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
      "Spock", title = "Science Officer" });		
   Console.WriteLine("Document 2: {0}", spockDocument.Resource.SelfLink); 
}

여기서 첫 번째 매개 변수는 특정 컬렉션이 아닌 데이터베이스에 대한 자체 링크입니다. 파티션 리졸버 없이는 불가능하지만 하나만 있으면 원활하게 작동합니다.

두 문서 모두 myfirstdb 데이터베이스에 저장되었지만, RangePartitionResolver가 제대로 작동하는 경우 Kirk는 A부터 M까지의 컬렉션에 저장되고 Spock은 N부터 Z까지의 컬렉션에 저장된다는 것을 알고 있습니다.

다음 코드에 표시된대로 CreateDocumentClient 작업에서이를 호출 해 보겠습니다.

private static async Task CreateDocumentClient() {
   // Create a new instance of the DocumentClient 
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
      await CreateCollections(client);  
      RegisterRangeResolver(client);  
      await CreateDocumentsAcrossPartitions(client); 
   } 
}

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

**** Create Documents Across Partitions **** 
Document 1: dbs/Ic8LAA==/colls/Ic8LAO2DxAA=/docs/Ic8LAO2DxAABAAAAAAAAAA==/ 
Document 2: dbs/Ic8LAA==/colls/Ic8LAP12QAE=/docs/Ic8LAP12QAEBAAAAAAAAAA==/

두 문서의 자체 링크는 두 개의 개별 컬렉션에 존재하기 때문에 리소스 ID가 다릅니다.