📜  DocumentDB-分区

📅  最后修改于: 2020-11-28 13:51:10             🧑  作者: Mango


当数据库开始增长到超过10GB时,您可以简单地通过创建新集合进行扩展,然后将数据分散或分区到越来越多的集合中。

具有10GB容量的单个集合迟早将不足以包含您的数据库。现在10GB听起来可能不是很大,但是请记住,我们正在存储JSON文档,它只是纯文本,即使考虑索引的存储开销,您也可以在10GB中容纳很多纯文本文档。

在扩展性方面,存储并不是唯一的问题。一个S3集合可获得的最大吞吐量是每秒两千半请求单元。因此,如果需要更高的吞吐量,则还需要通过对多个集合进行分区来进行扩展。横向扩展分区也称为水平分区

有许多方法可用于使用Azure DocumentDB进行数据分区。以下是最常见的策略-

  • 溢出分区
  • 范围分区
  • 查找分区
  • 哈希分区

溢出分区

溢出分区是最简单的策略,因为没有分区键。当您不确定很多事情时,通常是一个不错的选择。您可能不知道是否需要扩展到单个集合之外,或者可能需要添加几个集合,或者添加速度可能要快得多。

  • 溢出分区从一个集合开始,没有分区键。

  • 集合开始增长,然后增长更多,然后又增长,直到您开始接近10GB的限制。

  • 当您达到90%的容量时,您将溢出到一个新集合中并开始将其用于新文档。

  • 一旦数据库扩展到更大数量的集合,您可能会希望转向基于分区键的策略。

  • 这样做时,您需要根据要迁移的策略将文档移至不同的集合中,从而重新平衡数据。

范围分区

最常见的策略之一是范围分区。使用这种方法,您可以确定文档的分区键可能属于的值范围,并将该文档定向到与该范围相对应的集合。

  • 日期通常与该策略一起使用,在该策略中,您创建一个集合来保存属于定义的日期范围内的文档。当定义的范围足够小时,您可以确定没有任何集合会超出其10GB的限制。例如,在某些情况下,单个集合可以合理地处理整个月的文档。

  • 多数用户正在查询当前数据(也可能是本月或上个月的数据)的情况也可能是这种情况,但用户很少搜索更旧的数据。因此,您将从6月开始购买S3系列,这是您可以购买的最昂贵的系列,并且可以提供最佳的吞吐量。

  • 在7月份,您购买了另一个S3集合来存储7月份的数据,并且还将6月份的数据缩减为便宜的S2集合。然后在八月,您将获得另一个S3集合,并将七月缩小到S2,六月则缩小到S1。情况一个月又一个月地变化,您始终要使当前数据可用于高吞吐量,而较旧的数据将在较低吞吐量下保持可用。

  • 只要查询提供了分区键,就只查询需要查询的集合,而不会像溢出溢出分区那样查询数据库中的所有集合。

查找分区

使用查找分区,您可以定义一个分区图,该分区图根据文档的分区键将文档路由到特定的集合。例如,您可以按区域进行分区。

  • 将所有美国文件存储在一个集合中,将所有欧洲文件存储在另一个集合中,并将来自任何其他地区的所有文件存储在第三集合中。

  • 使用此分区图,查找分区解析器可以基于分区键(每个文档中包含的region属性)找出要在其中创建文档的集合以及要查询的集合。

哈希分区

在哈希分区中,将根据哈希函数的值分配分区,从而使您可以在多个分区之间均匀分配请求和数据。

这通常用于对从大量不同客户端生成或使用的数据进行分区,并且对于存储用户配置文件,目录项等很有用。

让我们看一个使用.NET SDK提供的RangePartitionResolver进行范围分区的简单示例。

步骤1-创建一个新的DocumentClient,我们将在CreateCollections任务中创建两个集合。一个包含针对用户ID以A到M开头的用户的文档,另一个包含针对用户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” }); 
}

步骤2-为数据库注册范围解析器。

步骤3-创建一个新的RangePartitionResolver < 字符串>,这是我们分区键的数据类型。构造函数有两个参数,分区键的属性名和一个字典,即分片图或分区图,这只是我们为解析程序预定义的范围和相应集合的列表。

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(
      "userId", new Dictionary, string>() {
      { new Range("A", "M\uffff"), "dbs/myfirstdb/colls/CollectionAM" },
      { new Range("N", "Z\uffff"), "dbs/myfirstdb/colls/CollectionNZ" },
   });
    
   client.PartitionResolvers["dbs/myfirstdb"] = resolver;
 }

必须在此处编码尽可能大的UTF-8值。否则,除了单个M之外,第一个范围在任何M上都不匹配,第二个范围中的Z同样如此。因此,您可以在此处将此编码值视为用于分区键匹配的通配符。

步骤4-创建解析器后,使用当前的DocumentClient将其注册到数据库。为此,只需将其分配给PartitionResolver的dictionary属性。

我们将针对数据库而不是通常的集合创建和查询文档,解析器将使用此映射将请求路由到适当的集合。

现在让我们创建一些文档。首先,我们将为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,因为它们存在于两个单独的集合中。