Azure DocumentDB 支持分片以水平方式分发数据和流量。 集合中的文档分为称为逻辑分片的区块。
水平扩展性的方法
Azure DocumentDB 提供了两种互补的方法,用于在群集中的物理分片之间分配数据和流量:
- 使用分片键对集合进行分片:通过选择分片键,将单个集合中的文档分布到各个物理分片上。 当集合的存储或吞吐量超过单个物理分片的容量时,请使用此方法。
- 跨分片放置集合:使集合保持未分片,并将 集合放置在特定物理分片上或将其并置。 当单个集合可放在同一个物理分片上,但希望控制哪些集合共享同一分片时,可使用这种方法。 例如,可以将缓存敏感集合隔离到其自己的分片上。
这些方法相互补充。 分片集合和未分片集合可以在同一集群中共存,因此你可以对那些规模增长到超出单个物理分片承载能力的集合进行分片,并将其余未分片集合分布在整个集群中。
逻辑分片
通过使用集合的文档结构中的指定分片键为每个集合单独定义分片。 将数据分成多个块,每个块对应一个逻辑分区。 分片键属性的每个唯一值对应的文档驻留在同一逻辑分片中。
对于插入到分片集合中的每个文档,对分片键属性的值进行哈希处理,以计算指定的逻辑分片。 服务提取并完全管理逻辑分片的位置以及群集中所有逻辑分片的分布。
包含分片键相同值的所有文档都属于同一逻辑分片。
例如,让我们考虑一个名为 Employees 的集合,其文档结构如下。
此表显示分片键值到逻辑分区的映射。
| 文档标识符 | 分片键值 | 逻辑分片 |
|---|---|---|
| "12345" | “史蒂夫·史密斯” | 分片 1 |
| "23456" | “Jane Doe” | 分片 2 |
| "34567" | “史蒂夫·史密斯” | 分片 1 |
| "45678" | “Michael Smith” | 分片 3 |
| "56789" | “Jane Doe” | 分片 2 |
集合的逻辑分片数没有限制。 集合可以拥有的逻辑分片数量,等同于每个文档中具有唯一分片键属性值的文档数量。
单个逻辑分片的大小也没有限制。
此外,该服务不会将交易限制在逻辑分片的范围内。 Azure DocumentDB 支持跨多个逻辑分片和群集中的多个物理分片适用的读取和写入事务。
物理分片
物理分片是负责保存数据和完成数据库事务的基础 计算机和磁盘 。 与逻辑分片不同,该服务在幕后管理物理分片。
创建群集时就定义了物理分片的数量,并且如果数据库大小随时间增长,可以增加分片的数量。 单个分片群集有一个物理分片(节点),完全负责群集的存储和数据库事务。 多分片群集在群集中的物理分片之间分布数据和事务量。
将逻辑分片映射到物理分片
添加新的逻辑分片时,群集将无缝更新逻辑到物理分片的映射。 在将新的物理分片添加到集群后,会更改对每个物理分片的地址空间分配,同时,逻辑分片会在整个集群中重新平衡。
用于映射逻辑分片和物理分片的哈希范围均匀分布在群集中的物理分片中。 每个物理分片拥有哈希范围的均匀大小的存储桶。 对于写入的每个文档,分片键属性的值经过哈希处理,哈希值确定文档到基础物理分片的映射。 在内部,多个逻辑分片映射到单个物理分片。 此外,逻辑分片永远不会在物理分片之间拆分,逻辑分片的所有文档仅映射到一个物理分片。
基于前面的示例使用具有两个物理分片的群集,此表显示了文档到物理分片的示例映射。
| 文档标识符 | 分片键值 | 逻辑分片 | 物理分片 |
|---|---|---|---|
| "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 自动管理副本集。
如何分片集合
注释
资源名称(例如表名、数据库名)和资源标签中不得包含任何个人、敏感或机密信息。 你在这些字段中输入的数据不被视为客户数据。
请考虑“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
})
跨物理分片的集合放置
默认情况下,服务会自动将每个集合放置在物理分片上,并将集合分布到群集中,以便均匀使用计算和存储。 对于大多数工作负荷,您无需管理其放置位置。
在某些情况下,需要显式控制集合所在的位置。 例如,仅当未筛选的查询保持完全处于内存中时,提供未筛选 find() 查询的集合才会表现良好。 当此类集合与其他高吞吐量集合共享物理分片时,它们会争用相同的内存中缓存。 然后,缓存淘汰会给最无法承受这种延迟的集合带来额外延迟。 可以将这些集合隔离到专用物理分片上,或将相关集合并置在同一分片上,而无需引入分片键或更改应用程序查询数据的方式。
集合放置功能仅适用于未分片集合。 分片集合已经按其分片键分布在整个集群中。
将集合移动到特定分片
使用 moveCollection 管理员命令将未分片的集合移动到特定的物理分片。 移动操作不会将集合转换为分片集合,也不会更改应用程序查询的方式。
use cosmicworks;
db.adminCommand({
"moveCollection": "cosmicworks.employee",
"toShard": "shard_0"
})
移动集合时,请考虑以下行为:
- 该集合必须未启用分片。 不能将分片集合固定在单个分片上。
- 如果集合已位于目标分片上,则该命令不执行任何操作。
- 创建集合后移动集合。 如果在创建集合后立即运行该命令,则可能会返回暂时性错误。 请稍等片刻,然后重试命令。
若要在同一分片上并置多个集合,请循环访问集合列表,并为每个命名空间运行一个 moveCollection 命令。
use cosmicworks;
const toShard = "shard_0";
const collections = ["employee", "department", "project"];
for (const coll of collections) {
db.adminCommand({ "moveCollection": `cosmicworks.${coll}`, "toShard": toShard });
}
查看集合位置
若要列出群集中的物理分片,请查询数据库中的shardsconfig集合。 每个 _id 值都是一个分片标识符,您可以将其传递给 toShard 参数。
db.getSiblingDB("config").shards.find({}, { "_id": 1 })
若要查看每个集合位于哪个分片上,请对 config 数据库中的 chunks 集合执行聚合,并按分片分组。 结果包含每个分片的一个条目,其中包含该分片上的集合命名空间列表。
db.getSiblingDB("config").chunks.aggregate([
{ "$group": { "_id": "$shard", "collections": { "$addToSet": "$ns" } } },
{ "$sort": { "_id": 1 } }
])
分片数据的最佳做法
除非集合的存储和事务量可以超过单个物理分片的容量,否则无需在 Azure DocumentDB 中对数据进行分片。 例如,该服务为每个分片提供 32 TB 磁盘。 如果集合需要 32 TB 以上,请将其分片。
在具有多个物理分片的集群中,不需要将每个集合都进行分片。 分片集合和未分片集合可以共存在同一集群中。 该服务以最佳方式将群集中的集合分布到均匀利用群集的计算和存储资源。
对于读取密集型应用程序,请根据最常见的查询模式选择分片键。 选择集合最常用的查询筛选器作为分片键,通过将搜索本地化为单个物理分片来优化数据库事务的最高百分比。
对于写入密集型且相比读取性能更看重写入性能的应用程序,请选择能够将数据均匀分布到各个物理分片上的分片键。 具有最高基数的分片键提供了统一分布数据的最佳机会。
为了获得最佳性能,请将逻辑分片的存储大小保持在 4 TB 以下。
为了获得最佳性能,应使逻辑分片在集群的各个物理分片之间按存储容量和请求量均匀分布。
集合不需要将分片键放置在特定的物理分片上。 可以将延迟敏感的未分片集合隔离到专用分片上,以便它不会与其他集合争用内存中缓存。 有关更多信息,请参阅 集合在物理分片之间的放置方式。