在阅读了有关分片、分片键和块迁移的文档后,我仍然无法掌握一个概念。
任何试图描述为什么不选择自动增量分片键的概念的人都告诉我,这是由于 mongo 将始终保持写入同一个分片的结果,因此这将增加负载,因为该分片将处理连续写入并迁移块。
我的问题是,为什么会这样?为什么自增值会导致写入请求总是被路由到一个特定的分片?分片的全部意义不是 mongos 应该知道什么是“最不”平衡的分片,而是写入这个分片,还是我理解错了?
提前致谢
问题是如果您使用单调递增的键,Mongo 无法确定分片的键范围。这是一个示例:
假设您有一个包含键 10,20,30,40,50,60 的集合如果 mongo 必须创建两个分片,它可能会假设键范围为:[10,30] 和 [31,60](或类似)。但是如果你继续写更大的键,它们总是会进入第二个范围。Mongo 会调整范围,但它永远无法知道下一个键是什么,它总是会进入最后一个范围。另一方面,如果您使用一些分布良好的键,您的写入序列将看起来更像:10、60、30、40、50... 并且在写入前两个键之后,mongo 将创建上述范围,并且您的下一个键将适合第一个或第二个。这将导致 mongo 之间共享性能,并且不会强制 mongo 进行重新平衡。
当前的分片机制存在这个问题。基本上,每个分片将提供其键位于连续范围内的数据。如果我们选择一个自增键,所有的写操作将只路由到一个分片,该分片提供比所有其他分片更大的键的数据。
这是使用自动增量键收集的问题。幸运的是,我们可以选择任何属性作为分片键。在大多数情况下,我们不会被迫使用“_id”作为分片键。如果对象具有合适的属性,例如博客应用程序的“用户名”,我们可以将其用作分片键。如果没有合适的属性,我们可以为每个对象添加一个属性列作为分片键,这个属性可以使用一些简单的哈希算法来计算。例如,如果我们有一个自动递增的 _id,我们可以简单地计算分片键:
sharding_key = _id % 257
在您拥有超过 257 个分片之前,上面的哈希应该足够好。
顺便说一句,自动生成的 ObjectId 不是 sharding-key 的好选择,因为它是基于时间的。
此外,MongoDB 2.3 中有一个新功能支持哈希键(请参阅https://jira.mongodb.org/browse/SERVER-2001和MongoDB 2.4 发行说明)。