MongoDB块与复合分片键平衡

时间:2015-01-09 05:46:59

标签: mongodb sharding

假设我有三个分片,使用复合键{ x: 1, y: 1 }作为集合,x有三个int值:1,2,3,y是随机的。

然后我为x = 1x = 2x = 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方,但文档没有说明如何选择移动哪个块。

感谢。

1 个答案:

答案 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及相关问题。

一些平衡建议包括:

  • 基于索引顺序的余额
  • 基于工作集估算的余额
  • 使用随机分片分配
  • load based balancing

这些建议中的大多数都要求平衡器监控整个群集中的其他指标,这会增加额外的复杂性。协调。例如,在您考虑需要跟踪这些指标(包括跨平台抽象)并且平衡器需要更复杂的策略来定平衡"阈值并忽略基于访问模式或服务器重启的临时不平衡。

默认平衡器策略有其他替代方法吗?

一般情况下,您可能希望使用默认的平衡器策略,但是如果您认为有更合适的方法来平衡数据,则需要考虑以下几种方法:

  1. 如果您希望数据具有某些特定的分片关联,则会有一个名为Sharding Zones (MongoDB 3.4+)Tag-Aware Sharding (MongoDB 3.2 and older)的高级分片选项,允许您将块的范围与特定的命名分片相关联。用于此的用例通常更加专业化,因为标记可能导致数据的故意不平衡。一些常见用例包括在分片群集中优化物理资源(例如tiered storage for "hot" and "cold" data),基于位置的数据分离(地理关联性)和balancing unsharded collections

  2. 虽然我们强烈建议您使用默认平衡器,但也可以disable the balancerManually Migrate Chunks使用mongo shell或者实施自己的平衡器脚本。