在 MongoDB 中使用聚合管道代替 map-reduce 作业

https://blueprints.launchpad.net/ceilometer/+spec/mongodb-aggregation-pipeline

问题描述

目前,当我们在 MongoDB 后端发起 GET “/v2/meter/<meter_type/statistics” 请求时,它会在 MongoDB 实例中启动一个原生 map-reduce 作业。测试和深入研究表明,该作业在处理大量样本(数百万以上)时性能不足。例如,在我的测试环境(16 GB RAM,8 CPU,1 TB 磁盘,15000000 样本)中,作业处理约 10000 个样本/秒。因此,处理 15M 样本需要约 1500 秒。这比默认 API 超时时间 1 分钟更长。

当然,使用 Gnocchi 调度器,我们不会遇到统计数据的问题,但计划仅使用 MongoDB 后端的用户在使用警报和生成用户报告时会遇到问题。

提议的变更

添加一个通过 MongoDB 聚合管道框架实现 get_meter_statistics 方法的实现。

来自 MongoDB 文档:“该框架基于数据处理管道的概念。文档进入一个多阶段管道,该管道将文档转换为聚合结果。最基本的管道阶段提供像查询一样工作的过滤器和修改输出文档形式的文档转换。其他管道操作提供按特定字段或字段对文档进行分组和排序的工具,以及聚合数组内容(包括文档数组)的工具。此外,管道阶段可以使用运算符来执行诸如计算平均值或连接字符串之类的任务。该管道使用 MongoDB 内的本机操作提供高效的数据聚合,并且是 MongoDB 中数据聚合的首选方法。”

我的研究表明,聚合管道比原生 map-reduce 作业快约 10 倍。因此,在相同的测试环境中处理 15M 样本需要 128 秒,而使用 map-reduce 需要 1500 秒。

管道聚合框架具有强大的功能和大量的运算符,可以提供对所有现有“statistics”功能的支持。

此实现仅影响 Ceilometer MongoDB 中统计请求的性能,不影响 API 或不同的后端。

风险

该框架具有指定的限制。它受到阶段 100 MB RAM 的限制,否则需要将中间阶段的结果写入磁盘上的临时文件。为了避免因 MongoDB>=2.6 中内存使用过多而导致故障,我们可以使用聚合命令中的 allowDiskUse=True 选项。此选项允许将中间暂存数据写入临时文件。因此,此方法的首要风险是磁盘上的可用空间以及磁盘写入和读取的性能缓慢。

因此,根据研究和 MongoDB 文档,“$sort” 命令为后续阶段创建最多的中间数据。因此,在实践中,此阶段准备的数据大小接近于新索引的大小。同时,索引字段的排序(例如我们 meter 集合中的时间戳)不需要在磁盘上进行任何额外数据。此请求使用现有索引进行排序。其他命令处理经过处理和分组的数据,并且仅在最坏的情况下(大量资源和按 resource_id 进行分组的单个请求)使用额外的空间。

尽管写入磁盘上的临时文件,但在此情况下聚合命令比 Map-Reduce 快几倍。

与 map-reduce 作业一样,此 MongoDB 机制对最终文档的大小也有限制,为 16 MB。

替代方案

我们还可以改进 map-reduce 作业的性能

数据模型影响

REST API 影响

安全影响

Pipeline 影响

其他最终用户影响

性能/可扩展性影响

改进 GET “/v2/<meter_name>/statistics” 请求的性能。

其他部署影响

开发者影响

实现

负责人

主要负责人

ityaptin

持续维护者

idegtiarev

工作项

  • 使用聚合管道框架实现 get_meter_statistics 函数

未来生命周期

依赖项

测试

  • 当前测试正在检查“statistics”请求的正确工作

文档影响

参考资料

http://docs.mongodb.org/v2.4/core/aggregation-introduction/