我正在测试 MongoDB 上的分片,因为我的集合子集正在迅速增长,并正在寻找一种加快查询速度的方法。就像分片的想法一样,能够在单个查询上使用多个线程来加速它。
现在我发现,当你启用分片,或者实际上将一个 shardkey 添加到集合中时,查询响应时间显着增加了40%
to 100%
,只有当查询是在 mongos 而不是 mongod 上完成时。得到了一致的结果,所以我设置了一个测试,也许你可以帮助我找出为什么它变慢以及我做错了什么,或者它是否是 Mongo 分片的一个令人讨厌的错误/问题。
- 启动一个空的配置服务器
- 启动一个空的 mongod
- 启动 mongos
- 连接到 mongos
- 使用测试数据库
- 添加数据:
for(var i = 0; i < 200000; i++) { db.testcol.insert({field1: i}); }
- 添加索引:
db.testcol.ensureIndex({field1:1})
- 测试查询速度几次:
db.testcol.find({field1:{$gte: 0}}).explain();
在我的测试系统上,我得到了一致的300 ms
- 启用分片:
sh.enableSharding("testdb.testcol");
- 测试查询速度:仍然
300 ms
- 碎片收集:
sh.shardCollection("testdb.testcol", {field1:1})
再次测试查询速度几次:现在我得到了一致的
660 ms
响应时间!!!!这里发生了什么?我得到完全相同的结果集,但现在响应时间显着增加。一切都是本地主机。现在直接连接mongod
use testdb
- 使用相同的查询进行测试:
db.testcol.find({field1:{$gte: 0}}).explain();
您将看到 300 毫秒的响应时间。因此,通过 mongos 对集合进行分片后,响应时间会显着增加。您需要 2 台机器才能获得与分片之前相同的响应时间。这不应该是正确分片的想法,还是我在这里遗漏了一点,而不仅仅是传播数据而不是提高性能?
补充: 1. 用不同的块大小测试它,1块,1000块。对响应时间没有影响 2. 监控 CPU 使用率并且所有 CPU 都在 mongod 上完成,mongos 不做任何事情。看起来当 mongod 查询一个分片集合(来自 mongos 的查询)时,与直接在 mongod 上执行的同一集合上的查询相比,它具有很大的 CPU。3. 嗅探查询,但是从 mongos 到 mongod 的查询在分片前和分片后是相同的。
- 另一个有趣的发现!看看下面的过程:
mongos> db.testcol.find({field1: {$gte: 0}},{_id:0,field1:1}).explain();
{
"cursor" : "BtreeCursor field1_1",
"isMultiKey" : false,
"n" : 5000000,
"nscannedObjects" : 0,
"nscanned" : 5000000,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 5000000,
"scanAndOrder" : false,
"indexOnly" : true,
"nYields" : 6,
"nChunkSkips" : 0,
"millis" : 4660,
"indexBounds" : {
"field1" : [
[
0,
1.7976931348623157e+308
]
]
},
"server" : "jvangaalen-PC:27020",
"millis" : 4660
}
mongos> sh.shardCollection("testdb.testcol",{field1:1});
{ "collectionsharded" : "testdb.testcol", "ok" : 1 }
mongos> db.testcol.find({field1: {$gte: 0}},{_id:0,field1:1}).explain();
{
"clusteredType" : "ParallelSort",
"shards" : {
"192.168.11.250:27020" : [
{
"cursor" : "BtreeCursor field1_1",
"isMultiKey" : false,
"n" : 5000000,
"nscannedObjects" : 5000000,
"nscanned" : 5000000,
"nscannedObjectsAllPlans" : 5000000,
"nscannedAllPlans" : 5000000,
"scanAndOrder" : false,
"indexOnly" : true,
"nYields" : 10,
"nChunkSkips" : 0,
"millis" : 9378,
"indexBounds" : {
"field1" : [
[
0,
1.7976931348623157e+308
]
]
},
"server" : "jvangaalen-PC:27020"
}
]
},
"cursor" : "BtreeCursor field1_1",
"n" : 5000000,
"nChunkSkips" : 0,
"nYields" : 10,
"nscanned" : 5000000,
"nscannedAllPlans" : 5000000,
"nscannedObjects" : 5000000,
"nscannedObjectsAllPlans" : 5000000,
"millisShardTotal" : 9378,
"millisShardAvg" : 9378,
"numQueries" : 1,
"numShards" : 1,
"indexBounds" : {
"field1" : [
[
0,
1.7976931348623157e+308
]
]
},
"millis" : 9426
}
分片前:4660 ms
响应时间。分片后:9426 ms
响应时间。
索引的使用方式相同。一个区别是nscannedobjects
which was0
和 now 是5000000
(所有文档)。为什么nscannedobjects
不是0
分片后?这可能是额外 CPU 的原因