- 文档数据库教程
- DocumentDB - 主页
- DocumentDB - 简介
- DocumentDB - 优点
- DocumentDB - 环境设置
- DocumentDB - 创建帐户
- DocumentDB - 连接帐户
- DocumentDB - 创建数据库
- DocumentDB - 列出数据库
- DocumentDB - 删除数据库
- DocumentDB - 创建集合
- DocumentDB - 删除集合
- DocumentDB - 插入文档
- DocumentDB - 查询文档
- DocumentDB - 更新文档
- DocumentDB - 删除文档
- DocumentDB - 数据建模
- DocumentDB - 数据类型
- DocumentDB - 限制记录
- DocumentDB - 记录排序
- DocumentDB - 索引记录
- DocumentDB - 地理空间数据
- DocumentDB - 分区
- DocumentDB - 数据迁移
- DocumentDB - 访问控制
- DocumentDB - 可视化数据
- DocumentDB 有用资源
- DocumentDB - 快速指南
- DocumentDB - 有用的资源
- DocumentDB - 讨论
DocumentDB - 分区
当您的数据库开始增长超过 10GB 时,您只需创建新集合,然后将数据分布或分区到越来越多的集合中即可进行扩展。
迟早,具有 10GB 容量的单个集合将不足以容纳您的数据库。现在,10GB 听起来可能不是一个很大的数字,但请记住,我们存储的是 JSON 文档,它只是纯文本,即使考虑索引的存储开销,您也可以在 10GB 中容纳大量纯文本文档。
在可扩展性方面,存储并不是唯一需要考虑的问题。集合上可用的最大吞吐量是使用 S3 集合获得的每秒两个半千个请求单位。因此,如果您需要更高的吞吐量,那么您还需要通过使用多个集合进行分区来进行扩展。横向扩展分区也称为水平分区。
有许多方法可用于使用 Azure DocumentDB 进行数据分区。以下是最常见的策略 -
- 溢出分区
- 范围划分
- 查找分区
- 哈希分区
溢出分区
溢出分区是最简单的策略,因为没有分区键。当您对很多事情不确定时,这通常是一个不错的选择。您可能不知道您是否需要扩展到单个集合之外,或者您可能需要添加多少个集合,或者您可能需要以多快的速度添加它们。
溢出分区从单个集合开始,并且没有分区键。
该集合开始增长,然后增长得更多,然后更多,直到开始接近 10GB 限制。
当容量达到 90% 时,您将溢出到新集合并开始将其用于新文档。
一旦您的数据库扩展到更多数量的集合,您可能希望转向基于分区键的策略。
当您这样做时,您需要根据您要迁移到的策略将文档移动到不同的集合,从而重新平衡数据。
范围划分
最常见的策略之一是范围分区。通过这种方法,您可以确定文档的分区键可能属于的值范围,并将文档定向到与该范围相对应的集合。
此策略通常使用日期,您可以创建一个集合来保存定义的日期范围内的文档。当您定义足够小的范围时,您可以确信任何集合都不会超过其 10GB 限制。例如,可能存在这样的场景:单个集合可以合理地处理一整月的文档。
也可能是这样的情况,大多数用户正在查询当前数据,这可能是本月或上个月的数据,但用户很少搜索更旧的数据。因此,您从 6 月份开始购买 S3 系列,这是您可以购买的最昂贵的系列,并且可以提供您可以获得的最佳吞吐量。
7 月份,您购买另一个 S3 集合来存储 7 月份的数据,并且还将 6 月份的数据缩减为较便宜的 S2 集合。然后在 8 月,您会获得另一个 S3 系列,然后将 7 月缩减为 S2,6 月一直缩减为 S1。月复一月,您始终保持当前数据可用于高吞吐量,而旧数据则保持在较低吞吐量下可用。
只要查询提供分区键,就只会查询需要查询的集合,而不是像溢出分区那样查询数据库中的所有集合。
查找分区
通过查找分区,您可以定义分区映射,根据分区键将文档路由到特定集合。例如,您可以按区域进行分区。
将所有美国文档存储在一个集合中,将所有欧洲文档存储在另一个集合中,并将来自任何其他地区的所有文档存储在第三个集合中。
使用此分区映射和查找分区解析器可以根据分区键(即每个文档中包含的区域属性)确定在哪个集合中创建文档以及要查询哪些集合。
哈希分区
在哈希分区中,分区是根据哈希函数的值分配的,允许您在多个分区之间均匀分布请求和数据。
这通常用于对大量不同客户端生成或消耗的数据进行分区,并且对于存储用户配置文件、目录项等很有用。
让我们看一下使用 .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<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 之外的任何 Ms 匹配,第二个范围中的 Z 也同样如此。因此,您可以将这里的编码值视为用于匹配分区键的通配符。
步骤 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,因为它们存在于两个单独的集合中。