默认范围分片键mongodb

ren*_*ior 5 sharding mongodb

我有一个mongodb碎片,有2个碎片(比方说A和B),每个碎片有17GB的可用空间.我将包含对象ID的_id设置为分片键.

以下是用于设置db和collection的命令.

sh.enableSharding("testShard");
sh.shardCollection("testShard.shardedCollection", {_id:1});
Run Code Online (Sandbox Code Playgroud)

然后我尝试向mongos服务器发出4,000,000次插入查询.我执行脚本4次以下.

for(var i=0; i<1000000; i++){
  db.shardedCollection.insert({x:i});
}
Run Code Online (Sandbox Code Playgroud)

使用_id作为分片键,根据我的理解,所提到的4000000文档将适合1个分片,所有插入仅在分片中发生.

然而,结果并不像我预期的那样,在一个碎片中插入了大约1,300万个文件,在B碎片中插入了另外~270万个文件.

为什么会这样?是否在分片设置命令中缺少某些内容?或者我的理解是错误的,也许在mongodb中有类似默认范围的分片键?

如果有人可以共享默认范围分片键的行为(没有标记识别),将会非常有帮助.

下面是sh.status()结果

  shard key: { "_id" : 1 }
  chunks:
    B  5
    A  5
  { "_id" : { "$minKey" : 1 } } -->> { "_id" : ObjectId("540c703398c7efdea6037cbc") } on : B Timestamp(6, 0) 
  { "_id" : ObjectId("540c703398c7efdea6037cbc") } -->> { "_id" : ObjectId("540c703498c7efdea603bfe3") } on : A Timestamp(6, 1) 
  { "_id" : ObjectId("540c703498c7efdea603bfe3") } -->> { "_id" : ObjectId("540c704398c7efdea605d818") } on : A Timestamp(3, 0) 
  { "_id" : ObjectId("540c704398c7efdea605d818") } -->> { "_id" : ObjectId("540c705298c7efdea607f04e") } on : A Timestamp(4, 0) 
  { "_id" : ObjectId("540c705298c7efdea607f04e") } -->> { "_id" : ObjectId("540c707098c7efdea60c20ba") } on : B Timestamp(5, 1) 
  { "_id" : ObjectId("540c707098c7efdea60c20ba") } -->> { "_id" : ObjectId("540c7144319c0dbee096f7d6") } on : B Timestamp(2, 4) 
  { "_id" : ObjectId("540c7144319c0dbee096f7d6") } -->> { "_id" : ObjectId("540c7183319c0dbee09f58ad") } on : B Timestamp(2, 6) 
  { "_id" : ObjectId("540c7183319c0dbee09f58ad") } -->> { "_id" : ObjectId("540eb15ddace5b39fbc32239") } on : B Timestamp(4, 2) 
  { "_id" : ObjectId("540eb15ddace5b39fbc32239") } -->> { "_id" : ObjectId("540eb192dace5b39fbca8a84") } on : A Timestamp(5, 2) 
  { "_id" : ObjectId("540eb192dace5b39fbca8a84") } -->> { "_id" : { "$maxKey" : 1 } } on : A Timestamp(5, 3) 
Run Code Online (Sandbox Code Playgroud)

Mar*_*erg 5

正如@LalitAgarwal所指出的,默认情况下,ObjectIds产生一个错误的分片键。但是,如果您真的不在乎数据位于哪个分片上,而只希望在这些分片之间平均分配写操作和块,则很容易获得:

db.shardedCollection.ensureIndex({_id:"hashed"});
sh.enableSharding("testShard");
sh.shardCollection("testShard.shardedCollection", {_id:"hashed"});
Run Code Online (Sandbox Code Playgroud)

但是,这带来了一些(通常可以忽略不计)的缺点:

  1. 您仅具有分片的其他索引,没有其他用例
  2. 该索引将占用一些RAM,这是高负载生产节点上的宝贵资源
  3. 该人工索引在插入期间将需要写操作

一种更好的方法是找到一个非人工的分片密钥。有关详细信息,请阅读选择分片键的注意事项。简而言之:

  1. 查找一个字段或多个字段的组合,它们可以明确地标识每个文档,并且(组合在一起)彼此差异很大。理想情况下,无论如何,这些都应该是您要查询的字段。
  2. 使用此字段或字段组合作为您的_id。由于无论如何在_id字段上都需要一个索引,并且您查询这些字段,因此摆脱了不必要的索引。
  3. 使用选定的_id字段作为分片键。


Lal*_*wal 2

是的,你是对的,它应该进入单个碎片。但是,虽然在单个分片上进行插入,但平衡器也会平衡分片并将块移动到其他分片。

话虽如此,您应该做的是通过从 mongos 调用以下命令来停止/禁用平衡器。

http://docs.mongodb.org/manual/reference/method/sh.disableBalancing/#sh.disableBalancing

sh.disableBalancing(namespace)
//namespace     string  The namespace of the collection.
Run Code Online (Sandbox Code Playgroud)

完成后,启动插入件并查看所有插入件的去向。

对于 _id 字段分片,您还可以查看此处:

http://docs.mongodb.org/manual/faq/sharding/#can-you-shard-on-the-id-field

Be aware that ObjectId() values, which are the default value of the _id field, 
increment as a timestamp. As a result, when used as a shard key, all new documents
inserted into the collection will initially belong to the same chunk on a single 
shard. Although the system will eventually divide this chunk and migrate its contents 
to distribute data more evenly, at any moment the cluster can only direct insert 
operations at a single shard. This can limit the throughput of inserts. If most of 
your write operations are updates, this limitation should not impact your performance. 
However, if you have a high insert volume, this may be a limitation.
Run Code Online (Sandbox Code Playgroud)