我正在研究节点后端尝试通过mongoose优化对mongodb的非常繁重的查询。预期的返回大小是相当大的,但由于某些原因,当我发出请求时,节点开始消耗大量内存,例如200mb +用于单个大请求。
考虑到大多数情况下回报的大小小于10mb,这似乎并不合适。它完成后也拒绝放弃内存,我知道这可能只是V8 GC执行其默认行为,但我担心的是单个find()请求消耗的大量内存。
我通过测试find()调用将其隔离。完成调用后,它会执行一些后处理,然后将数据发送到回调,所有这些都在匿名函数中。我尝试使用querystream而不是model.find(),但它没有显示真正的改进。
环顾四周没有得到任何回复,所以我会问,有没有一种已知的方法来减少,控制或优化mongoose的内存使用量?有谁知道为什么这么多的内存被用于一次通话?
修改
根据Johnny和Blakes的建议,使用精简()和流媒体的混合,并使用暂停和恢复,极大地改善了运行时和内存使用。谢谢!
答案 0 :(得分:7)
只要您只需要纯JavaScript文档而不是完整的Mongoose doc实例,就可以使用lean选项进行Mongoose查询。这样可以提高性能并减少内存使用量。
model.find().lean().exec(function(err, docs) {...});
您还可以将lean()
与流式处理相结合,这样可以进一步减少内存使用量。
var stream = model.find().lean().stream();
答案 1 :(得分:6)
默认的mongoose .find()
当然会将所有结果作为“数组”返回,因此总是会使用大量结果的内存,因此这会留下“流”接口。
这里的基本问题是你正在使用stream接口(因为它继承自基本节点流),每个数据事件“触发”并且相关的事件处理程序被连续执行。
这意味着即使使用“流”,您在事件处理程序中的后续操作也会“堆叠”起来,至少消耗大量内存并且如果在那里发生了进一步的异步进程,可能会占用调用堆栈
因此,您可以做的最好的事情是开始“限制”流处理中的操作。这就像调用.pause()
方法一样简单:
var stream = model.find().stream(); // however you call
stream.on("data",function() {
// call pause on entry
stream.pause();
// do processing
stream.resume(); // then resume when done
});
因此.pause()
会停止正在发出的流中的事件,这样就可以在继续之前完成事件处理程序中的操作,这样它们就不会立即出现。
当您的处理代码完成后,您可以直接在块中调用.resume()
,如此处所示,在块内执行的任何异步操作的回调块内。请注意,相同的规则适用于异步操作,并且“all”必须在您应该调用resume之前发出完成信号。
还可以应用其他优化,您可以查看“队列处理”或“异步流控制”可用模块以帮助您通过某些并行执行来获得更高的性能。
但基本上认为.pause()
然后处理并.resume()
继续避免在处理过程中占用大量内存。
此外,请注意您的“输出”,并且如果为响应构建某些内容,请尝试再次使用“流”。如果你正在做的工作只是在内存中构建另一个变量,所有这一切都将是徒劳的,所以有助于意识到这一点。