【问题标题】:Analyzing MongoDb aggregation performance分析 MongoDb 聚合性能
【发布时间】:2014-12-02 05:36:35
【问题描述】:

我正在尝试从集合中获取聚合的毫秒 ( - 当我在每个分片上单独尝试查询时,响应时间是相同的。 - 检查分析输出,我只能看到高 timeLockedMicros 和 numYield。 - 在彩信图表中也找不到任何异常。 我觉得在这里忽略了一些愚蠢的事情。非常感谢任何有助于进一步分析的帮助。下面提供了我的集群和集合详细信息

集群 - 6 个 34 GB 的节点,4 台核心机器 (AWS m2.2xlarge) 数据大小 1,285 MB(每个分片 213 MB) 记录数 = 550 万(每个分片约 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" : {

    },

更新 谢谢威尔的及时回复。欣赏它。我喜欢你的新数据模型和索引。但是,恐怕这不适合我当前的数据,因为, - 99% 的记录对于 actionType.1 和 - 我们 99% 的查询将选择 actionType.1 所以我猜对 actionType.K 的索引没有多大帮助。

正如您在 #2 和 #3 中所建议的,我们已经在使用更新 MongoDb 的 Spark 集群进行预聚合。

关于我的查询的更多信息 我之前分享的查询只是一个示例,仅用于对性能进行基准测试。我的实际查询将在 Timestamp 上有 $match ,在一个或多个文件上有 $group 。 典型的生产查询将针对 30 天的数据。目前我的收藏只有 15 天的数据。我的目标是获得 30 天数据的亚秒级响应时间

顺便说一句,我今天做了更多分析 我收集了碎片并在我的 MacBook 上安装的本地 mongo 中恢复。相同的查询只用了 2 秒(在 AWS 实例中用了 4 秒) 这没有任何意义,因为 AWS 实例的功能至少是 MacBook(CPU 和内存)的 4 倍 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 mongo 实例中的数据是在过去 15 天内通过应用程序填充的。因此,我将 AWS mongo 上的转储作为单独的集合重新导入。查询这个新集合需要 2 秒,这与 MACBook 的速度相当。所以碎片化是肯定的原因之一。我计划稍后对碎片进行更多研究。 尽管碎片整理提高了性能,但它与我的 MacBook 花费相同的时间这一事实并没有意义,因为 AWS 实例的功能是其 4 倍。 然后我们查看了 cpu 利用率,发现 mongod 实例只使用了一个 CPU(共 4 个)来执行查询。我们现在计划在每台机器上安装 4 个分片来解决这个问题。如果您看到更好的方法,请告诉我。

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

【问题讨论】:

  • 您的聚合管道正在处理集合中的每个文档。如果它必须击中每个文档,它不会很快。您只是总结了几个字段值,因此更简单的做法是在执行插入/更新时跟踪运行总计。
  • 正确,但这是故意的。我只有 15 天的数据 (~200MB) 正在尝试进行基准测试。

标签: mongodb performance aggregation-framework


【解决方案1】:

我会尝试的事情:

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 }

然后在“actionType.k”上确保索引。如果您不打算过滤所有不同的键值,那么根据文档中键的密度,索引会有所帮助。如果您打算对每个键求和,则索引在这里无济于事。

2) Map-reduce 和/或将这些添加到 cron-job/setTimeout 计划中。同样,根据您的更新周期以及您在任何时候需要数据的准确性,设置如下:

  • 每小时处理所有“脏”结果
  • 将当前值添加到运行总计中
  • 标记为“干净”

如果您对此数据库执行仅插入操作,则此方法有效。

3) 如果键值定期更改(更新而不是插入),那么在更新主集合的同时进行更改日志插入可能会更好。

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

然后定期清空“更改”集合,将值汇总到不同的集合。

【讨论】:

    猜你喜欢
    • 2015-02-17
    • 1970-01-01
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    相关资源
    最近更新 更多