假设我有三个分片,使用复合键{ 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)
Run Code Online (Sandbox Code Playgroud)
我的假设是MongoDB不是那么聪明,它只是在节点间平衡块数,它不考虑复合键分组,我是对的吗?或者我错过了什么?
什么是平衡块的策略?我理解它是如何选择from侧面和to侧面的,但是文档没有说明它如何选择移动的块.
谢谢.
我的假设是MongoDB不是那么聪明,它只是在节点间平衡块数,它不考虑复合键分组,我是对的吗?或者我错过了什么?
你是正确的,因为MongoDB服务器(如3.4)并没有试图在默认情况下过度思考如何分配块.块表示分片键范围中的文档的逻辑范围(默认情况下高达64MB),并且一般目标是每个分片具有大致相等的数据分布(由块的数量代理).
但是,要将复合键分组放入上下文中,您需要考虑块分布如何影响读写用例.
查询以游标批量从服务器获取文档,该文档不能超过最大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().
Run Code Online (Sandbox Code Playgroud)
假设您没有更改批量或块大小的任何默认值,这意味着基于范围的查询{x, y}仍然可以从单个目标分片上的单个块范围填充多个批次(或者偶尔会多于一个,具体取决于文件和块的大小/分布).
分片的主要原因之一是增加写入吞吐量.根据您选择的分片键以及数据如何到达,将连续分片密钥块的数据分发到不同的分片可能会有好处,以避免潜在的热点.由于x在您的示例中只有三个值,因此在x不同分片上具有给定值的范围可以通过在分片之间并行写入来提高吞吐量.
我理解它是如何选择从侧面到侧面的,但是文档没有说明它如何选择移动的块.
在MongoDB手册中详细介绍了Sharded Collection Balancing的策略,但是短版本是平衡器等待直到超过某些阈值(具有最少和最多块的碎片之间的差异)并且余额轮将继续直到数字之间的差异该集合的任何两个分片上的块数少于两个或块迁移失败.
很难以适合所有工作负载和部署的方式概括平衡器策略.根据您的数据分布,分片键和访问模式,对于一个用例而言,相同的方法可能不支持您的方法.
有关这方面的一些讨论,请参阅SERVER-5047:在平衡和相关问题时更聪明地了解哪个块移动.
一些平衡建议包括:
这些建议中的大多数都要求平衡器监控整个群集中的其他指标,这会增加额外的复杂性和协调性.例如,通过一些负载指标(CPU,RAM,网络使用)进行平衡听起来很有希望,直到您认为需要跟踪这些指标(包括跨平台抽象)并且平衡器需要更复杂的策略来定义"平衡"阈值并忽略基于访问模式或服务器重启的临时不平衡.
通常,您可能希望使用默认的平衡器策略,但是如果您认为有更合适的方法来平衡数据,则需要考虑以下几种方法:
如果您希望数据具有某些特定的分片关联,则会有一个名为Sharding Zones(MongoDB 3.4+)或Tag-Aware Sharding(MongoDB 3.2及更早版本)的高级分片选项 ,允许您将块的范围与特定的命名分片相关联.用于此的用例通常更加专业化,因为标记可能导致数据的故意不平衡.一些常见的用例包括优化物理资源(例如,"热"和"冷"数据的分层存储),基于位置的数据分离(地理亲和性),以及平衡分片群集中的非分片集合.
虽然强烈建议使用默认平衡器,但也可以使用shell 禁用平衡器和手动迁移块,mongo也可以通过实现自己的平衡器脚本来禁用.