用于在 Azure DocumentDB 中实现水平可伸缩性的分片

Azure DocumentDB 支持分片以水平方式分发数据和流量。 集合中的文档分为称为逻辑分片的区块。

使用集合的文档结构中的指定分片键为每个集合单独定义分片。 然后,将数据存储到区块中,每个区块对应于逻辑分区。 分片键属性的每个唯一值对应的文档驻留在同一逻辑分片中。

对于插入到分片集合中的每个文档,分片键属性的值经过哈希处理,以计算指定的逻辑分片。 放置逻辑分片和分发群集中的所有逻辑分片的责任已从用户移除,并由服务完全管理。

逻辑分片

包含分片键相同值的所有文档都属于同一逻辑分片。

例如,让我们考虑一个名为 Employees 的集合,其文档结构如下。

此表显示分片键值到逻辑分区的映射。

文档 ID 分片键值 逻辑分片
"12345" “史蒂夫·史密斯” 分片 1
"23456" “Jane Doe” 分片 2
"34567" “史蒂夫·史密斯” 分片 1
"45678" “Michael Smith” 分片 3
"56789" “Jane Doe” 分片 2
  • 集合的逻辑分片数没有限制。 集合可以拥有的逻辑分片数量,等同于每个文档中具有唯一分片键属性值的文档数量。

  • 单个逻辑分片的大小也没有限制。

  • 此外,该服务不会将交易限制在逻辑分片的范围内。 Azure DocumentDB 支持跨多个逻辑分片和群集中的多个物理分片适用的读取和写入事务。

物理分片

物理分片是负责保存数据和完成数据库事务的基础 计算机和磁盘 。 与逻辑分片不同,该服务在幕后管理物理分片。

创建群集时就定义了物理分片的数量,并且如果数据库大小随时间增长,可以增加分片的数量。 单个分片群集有一个物理分片(节点),完全负责群集的存储和数据库事务。 多分片群集在群集中的物理分片之间分布数据和事务量。

将逻辑分片映射到物理分片

添加新的逻辑分片时,群集将无缝更新逻辑到物理分片的映射。 在将新的物理分片添加到集群后,会更改对每个物理分片的地址空间分配,同时,逻辑分片会在整个集群中重新平衡。

用于映射逻辑分片和物理分片的哈希范围均匀分布在群集中的物理分片中。 每个物理分片拥有哈希范围的均匀大小的存储桶。 对于写入的每个文档,分片键属性的值经过哈希处理,哈希值确定文档到基础物理分片的映射。 在内部,多个逻辑分片映射到单个物理分片。 此外,逻辑分片永远不会在物理分片之间拆分,逻辑分片的所有文档仅映射到一个物理分片。

基于前面的示例使用具有两个物理分片的群集,此表显示了文档到物理分片的示例映射。

文档 ID 分片键值 逻辑分片 物理分片
"12345" “史蒂夫·史密斯” 分片 1 物理分片 1
"23456" “Jane Doe” 分片 2 物理分片 2
"34567" “史蒂夫·史密斯” 分片 1 物理分片 1
"45678" “Michael Smith” 分片 3 物理分片 1
"56789" “Jane Doe” 分片 2 物理分片 2

物理分片容量

预配群集时选择的群集层决定了物理分片的 CPU 和内存容量。 同样,存储 SKU 确定物理分片的存储和 IOPS 容量。 较大的群集层提供更多的计算能力和更大的内存,而更大的存储磁盘则提供更多的存储和 IOPS。 读取繁重的工作负荷受益于更大的群集层,而写入繁重的工作负荷受益于更大的存储 SKU。 根据应用程序不断变化的需求创建群集后,可以纵向扩展和缩减群集层。

在多分片群集中,每个物理分片的容量相同。 纵向扩展群集层或存储 SKU 不会更改逻辑分片在物理分片上的位置。 纵向扩展作后,物理分片数保持不变,从而避免需要重新平衡群集中的数据。

物理分片的计算、内存、存储和 IOPS 容量决定了可用于逻辑分片的资源。 分片键如果在存储和请求量上没有均匀分布,可能会导致群集内存储和吞吐量的消耗不均衡。 热分区可能导致物理分片的利用不均衡,从而引发不可预知的吞吐量和性能问题。 因此,分片群集需要预先仔细规划,以确保随着应用程序需求随时间的变化,性能保持一致。

副本集

每个物理分片由一组副本组成,也称为副本集。 每个副本都托管数据库引擎的一个实例。 副本集使数据存储在物理分片中持久、高度可用且一致。 构成物理分片的每个副本都继承物理分片的存储和计算容量。 Azure DocumentDB 自动管理副本集。

分片数据的最佳做法

  • 除非集合的存储和事务量超过单个物理分片的容量,否则在 Azure DocumentDB 中不需要分片。 例如,该服务为每个分片提供 32 TB 磁盘。 如果集合需要 32 TB 以上,则应将其分片。

  • 不需要对具有多个物理分片的群集中的每个集合进行分片。 分片集合和未分片集合可以共存在同一集群中。 该服务以最佳方式将群集中的集合分布到尽可能均匀地利用群集的计算和存储资源。

  • 对于读密集型的应用程序,必须根据最常见的查询模式选择分片密钥。 应选择集合最常用的查询筛选器作为分片键,以便通过将搜索本地化为单个物理分片来优化数据库事务的最高百分比。

  • 对于写入密集型应用程序,应选择分片键以确保数据在物理分片之间均匀分布。 基数最高的分片键能最佳地实现尽可能均匀的分布。

  • 为了获得最佳性能,逻辑分片的存储大小应小于 4 TB。

  • 为了获得最佳性能,逻辑分片在存储和请求量方面应均匀分布在群集的物理分片之间。

如何分片集合

请考虑“cosmicworks”数据库和“employee”集合中的以下文档

{
    "firstName": "Steve",
    "lastName": "Smith",
    "companyName": "Microsoft",
    "division": "Azure",
    "subDivision": "Data & AI",
    "timeInOrgInYears": 7
}

以下示例在 cosmicworks 数据库中根据 firstName 属性对员工集合进行分片。

use cosmicworks;
sh.shardCollection("cosmicworks.employee", {"firstName": "hashed"})

还可以使用管理员命令对集合进行分片:

use cosmicworks;
db.adminCommand({
  "shardCollection": "cosmicworks.employee",
  "key": {"firstName": "hashed"}
})

虽然在集合的数据量显著增加后更改分片键并不理想,但可以使用 reshardCollection 命令来更改分片键。

use cosmicworks;
sh.reshardCollection("cosmicworks.employee", {"lastName": "hashed"})

还可以使用管理员命令重新分片集合:

use cosmicworks;
db.adminCommand({
  "reshardCollection": "cosmicworks.employee",
  "key": {"lastName": "hashed"}
})

最佳做法是在分片键属性上创建索引。

use cosmicworks;
db.runCommand({
  createIndexes: "employee",
  indexes: [{"key":{"firstName":1}, "name":"firstName_1", "enableLargeIndexKeys": true}],
  blocking: true
})

后续步骤