默认范围分片键mongodb

时间:2014-09-12 03:35:57

标签: mongodb sharding

我有一个带有2个分片的mongodb分片(比如A& B),每个分区有17GB的可用空间。我将包含对象ID的_id设置为分片键。

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

sh.enableSharding("testShard");
sh.shardCollection("testShard.shardedCollection", {_id:1});

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

for(var i=0; i<1000000; i++){
  db.shardedCollection.insert({x:i});
}

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

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

为什么会这样?是否在分片设置命令中缺少某些内容?或者我的理解是错误的,也许在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) 

2 个答案:

答案 0 :(得分:4)

正如@LalitAgarwal已经指出的那样,ObjectIds默认会生成一个错误的分片键。但是,如果您并不真正关心数据存在于哪个分片中,并且只想让写入操作和块在您的分片中均匀分布,那么很容易获得:

db.shardedCollection.ensureIndex({_id:"hashed"});
sh.enableSharding("testShard");
sh.shardCollection("testShard.shardedCollection", {_id:"hashed"});

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

  1. 您有一个额外的索引仅用于分片,而不是其他用例
  2. 这个索引会占用一些RAM,这是高负载生产节点的宝贵资源
  3. 此人工索引在插入期间需要写入操作
  4. 更好的方法是找到非人为的分片键。有关详细信息,请阅读Considerations for Selecting Shard Keys。简而言之:

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

答案 1 :(得分:2)

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

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

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

sh.disableBalancing(namespace)
//namespace     string  The namespace of the collection.

完成后,启动插件并查看所有插件的前进位置。

对于_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.