DocumentDB - Phân vùng

Khi cơ sở dữ liệu của bạn bắt đầu phát triển vượt quá 10GB, bạn có thể mở rộng quy mô chỉ đơn giản bằng cách tạo các bộ sưu tập mới và sau đó phân chia hoặc phân vùng dữ liệu của mình trên nhiều bộ sưu tập hơn.

Không sớm thì muộn, một bộ sưu tập duy nhất, có dung lượng 10GB, sẽ không đủ để chứa cơ sở dữ liệu của bạn. Bây giờ 10GB nghe có vẻ không phải là một con số quá lớn, nhưng hãy nhớ rằng chúng tôi đang lưu trữ tài liệu JSON, chỉ là văn bản thuần túy và bạn có thể chứa nhiều tài liệu văn bản thuần túy trong 10GB, ngay cả khi bạn xem xét chi phí lưu trữ cho các chỉ mục.

Lưu trữ không phải là mối quan tâm duy nhất khi nói đến khả năng mở rộng. Thông lượng tối đa có sẵn trên một bộ sưu tập là 2,5 nghìn đơn vị yêu cầu mỗi giây mà bạn nhận được với một bộ sưu tập S3. Do đó, nếu bạn cần thông lượng cao hơn, thì bạn cũng sẽ cần phải mở rộng quy mô bằng cách phân vùng với nhiều bộ sưu tập. Phân vùng theo tỷ lệ còn được gọi làhorizontal partitioning.

Có nhiều cách tiếp cận có thể được sử dụng để phân vùng dữ liệu với Azure DocumentDB. Sau đây là các chiến lược phổ biến nhất -

  • Phân vùng tràn
  • Phân vùng phạm vi
  • Phân vùng tra cứu
  • Phân vùng băm

Phân vùng tràn

Phân vùng tràn là chiến lược đơn giản nhất vì không có khóa phân vùng. Nó thường là một lựa chọn tốt để bắt đầu khi bạn không chắc chắn về nhiều thứ. Bạn có thể không biết liệu bạn có bao giờ cần mở rộng ra ngoài một bộ sưu tập duy nhất hay không hoặc có bao nhiêu bộ sưu tập bạn có thể cần thêm hoặc bạn có thể cần thêm chúng nhanh như thế nào.

  • Phân vùng tràn bắt đầu với một tập hợp duy nhất và không có khóa phân vùng.

  • Bộ sưu tập bắt đầu phát triển và sau đó phát triển thêm, và sau đó là một số nữa, cho đến khi bạn bắt đầu gần đạt đến giới hạn 10GB.

  • Khi bạn đạt đến 90% dung lượng, bạn chuyển sang một bộ sưu tập mới và bắt đầu sử dụng nó cho các tài liệu mới.

  • Khi cơ sở dữ liệu của bạn mở rộng ra một số lượng lớn hơn các bộ sưu tập, có thể bạn sẽ muốn chuyển sang chiến lược dựa trên khóa phân vùng.

  • Khi làm điều đó, bạn sẽ cần phải cân bằng lại dữ liệu của mình bằng cách di chuyển tài liệu sang các bộ sưu tập khác nhau dựa trên bất kỳ chiến lược nào bạn đang chuyển sang.

Phân vùng phạm vi

Một trong những chiến lược phổ biến nhất là phân vùng theo phạm vi. Với cách tiếp cận này, bạn xác định phạm vi giá trị mà khóa phân vùng của tài liệu có thể nằm trong đó và hướng tài liệu đến một tập hợp tương ứng với phạm vi đó.

  • Ngày thường được sử dụng với chiến lược này, trong đó bạn tạo một bộ sưu tập để lưu giữ các tài liệu nằm trong phạm vi ngày đã xác định. Khi bạn xác định phạm vi đủ nhỏ, nơi bạn tự tin rằng không có bộ sưu tập nào vượt quá giới hạn 10GB của nó. Ví dụ, có thể có một tình huống trong đó một bộ sưu tập duy nhất có thể xử lý hợp lý các tài liệu cho cả tháng.

  • Cũng có thể xảy ra trường hợp hầu hết người dùng đang truy vấn dữ liệu hiện tại, đó sẽ là dữ liệu của tháng này hoặc có thể là tháng trước, nhưng người dùng hiếm khi tìm kiếm dữ liệu cũ hơn nhiều. Vì vậy, bạn bắt đầu vào tháng 6 với bộ sưu tập S3, đây là bộ sưu tập đắt nhất mà bạn có thể mua và mang lại thông lượng tốt nhất mà bạn có thể nhận được.

  • Vào tháng 7, bạn mua một bộ sưu tập S3 khác để lưu trữ dữ liệu tháng 7 và bạn cũng chia tỷ lệ dữ liệu tháng 6 thành bộ sưu tập S2 rẻ hơn. Sau đó, vào tháng 8, bạn nhận được một bộ sưu tập S3 khác và chia tháng 7 xuống thành S2 và tháng 6 giảm dần xuống S1. Nó diễn ra, tháng này qua tháng khác, nơi bạn luôn giữ dữ liệu hiện tại có sẵn để có thông lượng cao và dữ liệu cũ hơn được giữ ở mức thông lượng thấp hơn.

  • Miễn là truy vấn cung cấp khóa phân vùng, chỉ tập hợp cần được truy vấn mới được truy vấn và không phải tất cả các tập hợp trong cơ sở dữ liệu giống như điều đó xảy ra với phân vùng tràn.

Phân vùng tra cứu

Với phân vùng tra cứu, bạn có thể xác định bản đồ phân vùng định tuyến tài liệu đến các bộ sưu tập cụ thể dựa trên khóa phân vùng của chúng. Ví dụ, bạn có thể phân vùng theo vùng.

  • Lưu trữ tất cả các tài liệu Hoa Kỳ trong một bộ sưu tập, tất cả các tài liệu châu Âu trong một bộ sưu tập khác và tất cả các tài liệu từ bất kỳ khu vực nào khác trong một bộ sưu tập thứ ba.

  • Sử dụng bản đồ phân vùng này và trình phân giải phân vùng tra cứu có thể tìm ra tập hợp nào để tạo tài liệu và tập hợp nào cần truy vấn, dựa trên khóa phân vùng, là thuộc tính vùng có trong mỗi tài liệu.

Phân vùng băm

Trong phân vùng băm, các phân vùng được gán dựa trên giá trị của một hàm băm, cho phép bạn phân phối đồng đều các yêu cầu và dữ liệu trên một số phân vùng.

Điều này thường được sử dụng để phân vùng dữ liệu được tạo ra hoặc tiêu thụ từ một số lượng lớn các máy khách riêng biệt và hữu ích để lưu trữ hồ sơ người dùng, các mục danh mục, v.v.

Hãy xem một ví dụ đơn giản về phân vùng phạm vi bằng cách sử dụng RangePartitionResolver do .NET SDK cung cấp.

Step 1- Tạo một DocumentClient mới và chúng tôi sẽ tạo hai bộ sưu tập trong tác vụ CreateCollections. Một sẽ chứa các tài liệu dành cho người dùng có ID người dùng bắt đầu từ A đến M và tài liệu còn lại chứa các ID người dùng từ N đế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 - Đăng ký trình phân giải phạm vi cho cơ sở dữ liệu.

Step 3- Tạo một RangePartitionResolver <string> mới, là kiểu dữ liệu của khóa phân vùng của chúng ta. Hàm tạo nhận hai tham số, tên thuộc tính của khóa phân vùng và từ điển là bản đồ phân đoạn hoặc bản đồ phân vùng, chỉ là danh sách các phạm vi và tập hợp tương ứng mà chúng ta đang xác định trước cho trình phân giải.

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;
 }

Cần mã hóa giá trị UTF-8 lớn nhất có thể ở đây. Hoặc nếu không thì phạm vi đầu tiên sẽ không khớp với bất kỳ Ms nào ngoại trừ một M duy nhất, và tương tự đối với Z trong phạm vi thứ hai. Vì vậy, bạn có thể nghĩ về giá trị được mã hóa này ở đây như một ký tự đại diện để khớp trên khóa phân vùng.

Step 4- Sau khi tạo trình phân giải, hãy đăng ký nó cho cơ sở dữ liệu với DocumentClient hiện tại. Để làm điều đó, chỉ cần gán nó vào thuộc tính từ điển của PartitionResolver.

Chúng tôi sẽ tạo và truy vấn các tài liệu dựa trên cơ sở dữ liệu, không phải một bộ sưu tập như bạn thường làm, trình phân giải sẽ sử dụng bản đồ này để định tuyến các yêu cầu đến các bộ sưu tập thích hợp.

Bây giờ chúng ta hãy tạo một số tài liệu. Đầu tiên, chúng tôi sẽ tạo một cho userId Kirk, và sau đó một cho 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); 
}

Tham số đầu tiên ở đây là một liên kết tự đến cơ sở dữ liệu, không phải là một tập hợp cụ thể. Điều này không thể thực hiện được nếu không có trình phân giải phân vùng, nhưng với trình giải quyết phân vùng, nó hoạt động liền mạch.

Cả hai tài liệu đã được lưu vào cơ sở dữ liệu myfirstdb, nhưng chúng tôi biết rằng Kirk đang được lưu trữ trong bộ sưu tập từ A đến M và Spock đang được lưu trữ trong bộ sưu tập từ N đến Z, nếu RangePartitionResolver của chúng tôi hoạt động bình thường.

Hãy gọi chúng từ tác vụ CreateDocumentClient như được hiển thị trong đoạn mã sau.

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); 
   } 
}

Khi đoạn mã trên được thực thi, bạn sẽ nhận được kết quả sau.

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

Như đã thấy, các liên kết tự của hai tài liệu có ID tài nguyên khác nhau vì chúng tồn tại trong hai tập hợp riêng biệt.