假设我有三个分片,使用复合键{ x: 1, y: 1 }
作为集合,x有三个int值:1,2,3,y是随机的。
然后我为x = 1
,x = 2
和x = 3
插入了相同数量的文档。我期待的是所有范围为x = 1
的块到shard1,x = 2
转到shard2,x = 3
转到shard3,然后我可以进行查询隔离。但输出是出乎意料的:
test.t6
shard key: { "x" : 1, "y" : 1 }
chunks:
shard0000 5
shard0002 5
shard0001 5
{ "x" : { "$minKey" : 1 }, "y" : { "$minKey" : 1 } } -->> { "x" : 1, "y" : 0 } on : shard0000 Timestamp(2, 0)
{ "x" : 1, "y" : 0 } -->> { "x" : 1, "y" : 11593 } on : shard0002 Timestamp(3, 0)
{ "x" : 1, "y" : 11593 } -->> { "x" : 1, "y" : 34257 } on : shard0000 Timestamp(4, 0)
{ "x" : 1, "y" : 34257 } -->> { "x" : 1, "y" : 56304 } on : shard0002 Timestamp(5, 0)
{ "x" : 1, "y" : 56304 } -->> { "x" : 1, "y" : 78317 } on : shard0000 Timestamp(6, 0)
{ "x" : 1, "y" : 78317 } -->> { "x" : 2, "y" : 3976 } on : shard0002 Timestamp(7, 0)
{ "x" : 2, "y" : 3976 } -->> { "x" : 2, "y" : 26497 } on : shard0000 Timestamp(8, 0)
{ "x" : 2, "y" : 26497 } -->> { "x" : 2, "y" : 48788 } on : shard0002 Timestamp(9, 0)
{ "x" : 2, "y" : 48788 } -->> { "x" : 2, "y" : 74377 } on : shard0000 Timestamp(10, 0)
{ "x" : 2, "y" : 74377 } -->> { "x" : 2, "y" : 99329 } on : shard0002 Timestamp(11, 0)
{ "x" : 2, "y" : 99329 } -->> { "x" : 3, "y" : 25001 } on : shard0001 Timestamp(11, 1)
{ "x" : 3, "y" : 25001 } -->> { "x" : 3, "y" : 49652 } on : shard0001 Timestamp(9, 2)
{ "x" : 3, "y" : 49652 } -->> { "x" : 3, "y" : 72053 } on : shard0001 Timestamp(9, 4)
{ "x" : 3, "y" : 72053 } -->> { "x" : 3, "y" : 97436 } on : shard0001 Timestamp(10, 2)
{ "x" : 3, "y" : 97436 } -->> { "x" : { "$maxKey" : 1 }, "y" : { "$maxKey" : 1 } } on : shard0001 Timestamp(10, 3)
我的假设是MongoDB并不那么聪明,它只是在节点之间平衡块数,它不考虑复合键分组,我是对的吗?或者我错过了什么?
平衡块时的策略是什么?我理解它如何选择from
方和to
方,但文档没有说明如何选择移动哪个块。
感谢。
答案 0 :(得分:6)
我的假设是MongoDB并不聪明,它只是平衡块数 在节点之间,不考虑复合密钥分组, 我对吗?或者我错过了什么?
你是正确的,因为MongoDB服务器(如3.4)并没有试图在默认情况下过度思考如何分发块。块表示分片键范围(by default up to 64MB)中的文档的逻辑范围,并且一般目标是每个分片具有大致相等的数据分布(由代码块数代理)。
但是,要将复合键分组放入上下文中,您需要考虑块分布如何影响读写用例。
查询从cursor batches中的服务器获取文档,该文档不能超过最大BSON文档大小(目前为16MB):
For most queries, the first batch returns 101 documents or just enough documents
to exceed 1 megabyte. Subsequent batch size is 4 megabytes. To override the
default size of the batch, see batchSize() and limit().
假设您没有更改批量或块大小的任何默认值,这意味着{x, y}
上的基于范围的查询仍然可以从单个块范围填充多个批次目标分片(或偶尔不止一个,取决于文档和块的大小/分布)。
分片的主要原因之一是增加写入吞吐量。根据您的choice of shard key以及数据的到达方式,将连续分片密钥块的数据分发到不同的分片可能会有好处,以避免潜在的热点。由于您的示例中只有x
的三个值,因此在不同分片上具有给定值x
的范围可以通过在分片之间并行写入来提高吞吐量。
我理解它是如何选择从侧面到侧面的,但是文档并没有说明如何选择移动哪个块。
MongoDB手册详细介绍了Sharded Collection Balancing的策略,但简短版本是平衡器等待超过certain thresholds(碎片与最少和最多块之间的差异)和余额round将继续,直到该集合的任何两个分片上的块数之差小于2或块迁移失败。
很难以适合所有工作负载和部署的方式概括平衡器策略。根据您的数据分布,分片键和访问模式,一个用例的优秀方法可能不支持您的。
有关此问题的一些讨论,请参阅SERVER-5047: be smarter about which chunk moves when balancing及相关问题。
一些平衡建议包括:
这些建议中的大多数都要求平衡器监控整个群集中的其他指标,这会增加额外的复杂性。协调。例如,在您考虑需要跟踪这些指标(包括跨平台抽象)并且平衡器需要更复杂的策略来定平衡"阈值并忽略基于访问模式或服务器重启的临时不平衡。
一般情况下,您可能希望使用默认的平衡器策略,但是如果您认为有更合适的方法来平衡数据,则需要考虑以下几种方法:
如果您希望数据具有某些特定的分片关联,则会有一个名为Sharding Zones (MongoDB 3.4+)或Tag-Aware Sharding (MongoDB 3.2 and older)的高级分片选项,允许您将块的范围与特定的命名分片相关联。用于此的用例通常更加专业化,因为标记可能导致数据的故意不平衡。一些常见用例包括在分片群集中优化物理资源(例如tiered storage for "hot" and "cold" data),基于位置的数据分离(地理关联性)和balancing unsharded collections。
虽然我们强烈建议您使用默认平衡器,但也可以disable the balancer和Manually Migrate Chunks使用mongo
shell或者实施自己的平衡器脚本。