2014-12-02 128 views
4

我试图从集合中获取毫秒(<秒)的响应时间。但是,即使对于小数据量(〜200MB),它现在也需要3-5秒。我收集的这个系列产品的预期数据大约是每个碎片100GB。 我已经检查了以下内容
- 当我在每个分片上单独尝试查询时,响应时间相同。 - 检查了性能分析输出,我只能看到高时间锁定的微秒和numYield。 - 在MMS图表中找不到任何不寻常的东西。 我觉得这里过分愚蠢的东西。任何帮助进一步分析这一点高度赞赏。下面提供分析MongoDb聚合性能

群集我的群集和收集细节 - 34 GB,4个芯机(AWS m2.2xlarge) 数据大小 1285 MB(每分片213 MB) 没有记录的6个节点= 5500000(〜每碎片1 M)

记录样品

{ 
    "_id" : { 
     "ItemID" : 105182, 
     "DeviceType" : 16, 
     "ItemVersionID" : 117971, 
     "Timestamp" : ISODate("2014-11-14T00:00:00Z"), 
     "RecordType" : 1 
    }, 
    "Dim1ID" : 102260, 
    "Dim2ID" : 313, 
    "Dim3ID" : 1, 
    "actionType" : { 
     "1" : 66, 
     "47" : 66, 
     "42" : 72, 
     "46" : 130 
    } 
} 

查询

db.AggregateCollection.aggregate({ "$group" : { "_id" : { } , "type1" : { "$sum" : "$actionType.1"} , "type2" : { "$sum" : "$actionType.2"}}}) 

资料统计(从一个碎片)

"keyUpdates" : 0, 
    "numYield" : 79, 
    "lockStats" : { 
     "timeLockedMicros" : { 
      "r" : NumberLong(2981456), 
      "w" : NumberLong(0) 
     }, 
     "timeAcquiringMicros" : { 
      "r" : NumberLong(3756), 
      "w" : NumberLong(4) 
     } 
    }, 
    "responseLength" : 157, 
    "millis" : 3268, 
    "execStats" : { 

    }, 

UPDATE 感谢您将为迅速作出反应。 Apreciate它。我喜欢你的新数据模型和索引。不过,恐怕不适合我目前的数据,因为, - 记录的99%,将有actionType.1 SOEM价值和 - 我们的查询的99%将选择actionType.1 上actiionType.K止跌所以指数我猜想没什么帮助。

正如您在#2 &#3中所建议的那样,我们已经在使用Spark群集进行预聚集,该群集会上传MongoDb。

多一点点关于我的查询 我刚才共享查询只是一个样本之一,只是用来基准性能。我的实际查询将在Timestamp上有$匹配,在一个或多个fileds上有$ group。 典型的生产查询将用于30天的数据。目前我的收藏只有15天的数据。我的目标是获得亚秒级的响应时间为30天的数据

顺便说一句,我今天 做了一些更多的分析我toook碎片的转储和安装在我的MacBook本地蒙戈恢复。相同的查询仅需2秒(在AWS isntance中花了4秒钟) 没有意义,因为AWS实例至少比MacBook强4倍(均为CPU &内存) MacBook Air - http://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-4250U+%40+1.30GHz AWS m2.2xlarge实例 - http://www.cpubenchmark.net/cpu.php?cpu=Intel+Xeon+E5-2665+%40+2.40GHz

我怀疑碎片监守在AWS数据蒙戈实例是通过一个应用程序人口在过去15天。所以我重新将AWS mongo上的转储作为单独的集合导入。查询这个新的收藏需要2秒,这是相当于MAcBook的速度。所以碎片化是确定的一个原因。我计划在以后对碎片做更多的研究。 尽管对改进的perfromace进行了碎片整理,但它与我的MacBook花费相同的时间并没有什么意义,因为AWS isntance功能强大4倍。 然后我们查看了CPU利用率,发现mongod实例只使用一个CPU(4个中的一个)来执行查询。我们现在计划在每台机器上安装4个碎片来解决这个问题。如果你看到更好的方法,请告诉我。

还有一件事,我知道我的查询必须扫描整个集合,但2秒钟扫描~200MB的数据对我来说似乎非常高。这是预计还是我错过了什么?

+0

您的聚合管道正在处理集合中的每个文档。如果它必须击中每个文档,它不会很快。你只是总结了几个字段值,所以更容易做的是在插入/更新时跟踪运行总数。 – wdberkeley 2014-12-02 08:31:48

+0

正确,但这是故意的。我只有15天的数据(〜200MB),我正在尝试进行基准测试。 – 2014-12-03 00:54:02

回答

2

事情我想尝试:

1)你在这使得分组很困难的方式组织数据。如果你像这样组织文档,你可能会得到更好的结果:

{ 
    ... 
    "actionType" : [{k:1, v:66}, {k:47, v:66}, {k:42, v:72}, {k:46, v:130}] 
} 

这将允许您创建'actionType.k'索引。然后,你可以做一个匹配该索引你的整体数据集减少到你想要的确切actionTypes此聚集,在您的查询是:

db.action.aggregate([{$unwind: '$actionType'}, 
     {$group:{_id:'$actionType.k', t:{$sum:'$actionType.v'} } }]); 
//output 
{ "_id" : 46, "t" : 130 } 
{ "_id" : 42, "t" : 72 } 
{ "_id" : 47, "t" : 66 } 
{ "_id" : 1, "t" : 66 } 

然后ensureIndex上“actionType.k”。如果您不打算过滤所有不同的键值,索引将会有所帮助,具体取决于文档中键的密度。如果您计划汇总每个密钥,那么索引在这里将无济于事。

2)在cron-job/setTimeout时间表上映射和/或添加它们。此外,根据您的更新周期,以及如何准确,你需要在任何一个时间的数据,建立类似:

  • 每隔一小时过程中的所有“脏”的结果
  • 添加当前值运行总计
  • 标记为'干净'

如果您只对此数据库执行插入操作,则可以使用该功能。 3)如果关键值定期更新(更新而不是插入),那么在更新日志插入时可能会更好,因为更新日志插入与主集合更新同时发生。

db.changes.insert({key:44, change:2}); 
db.changes.insert({key:34, change:-2}); 

然后常规地清空'changes'集合,将这些值相加到不同的集合中。

+0

感谢Will,请查看问题的更新 – 2014-12-03 00:51:49