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 自动管理副本集。
如何分片集合
请考虑“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"
})
移动集合时,请考虑以下行为:
- 集合必须未分片。 不能将分片集合固定到单个分片。
- 如果集合已在目标分片上,则命令为 no-op。
- 创建集合后移动集合。 如果在创建集合后立即运行该命令,则可能会返回暂时性错误。 请稍等片刻,然后重试命令。
若要在同一分片上并置多个集合,请循环访问集合列表,并为每个命名空间运行一个 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 })
若要查看哪个分片保存每个集合,请按分片聚合数据库和组中的chunksconfig集合。 结果包含每个分片的一个条目,其中包含该分片上的集合命名空间列表。
db.getSiblingDB("config").chunks.aggregate([
{ "$group": { "_id": "$shard", "collections": { "$addToSet": "$ns" } } },
{ "$sort": { "_id": 1 } }
])
分片数据的最佳做法
除非集合的存储和事务量可以超过单个物理分片的容量,否则无需在 Azure DocumentDB 中对数据进行分片。 例如,该服务为每个分片提供 32 TB 磁盘。 如果集合需要 32 TB 以上,请将其分片。
无需对具有多个物理分片的群集中的每个集合进行分片。 分片集合和未分片集合可以共存在同一集群中。 该服务以最佳方式将群集中的集合分布到均匀利用群集的计算和存储资源。
对于读取密集型应用程序,请根据最常见的查询模式选择分片键。 选择集合最常用的查询筛选器作为分片键,通过将搜索本地化为单个物理分片来优化数据库事务的最高百分比。
对于支持读取性能的写入密集型应用程序,请选择一个分片键,该键均匀地在物理分片之间分布数据。 具有最高基数的分片键提供了统一分布数据的最佳机会。
为了获得最佳性能,请将逻辑分片的存储大小保持在 4 TB 以下。
为了获得最佳性能,请在存储和请求卷中均匀分布逻辑分片,并跨群集的物理分片分布。
集合不需要将分片键放置在特定的物理分片上。 可以将延迟敏感的未分片集合隔离到专用分片上,以便它不会与其他集合争用内存中缓存。 有关详细信息,请参阅 跨物理分片的集合放置。