当在node.js中保存大文档时,MongoDB-mongoose使用高cpu

我正在开发一个EC2托pipe的像素跟踪应用程序,每次请求video广告时都会调用这个应用程序,因此它会跟踪何时启动,完成以及是否进行了点击操作。 我正在使用node.js,因为我想尽可能快地响应mongoDB / Mongoose,因为它就像服务器日志结构一样。 几乎每毫秒都会收到请求。 但是将文件存储到集合中时,占用大量的CPU几乎100%,并且在最后node.js启动错误:

GET /pixel/impression/ad1 200 1ms FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory 

我认为这是mongoose的操作,当我移除部件的时候,它就占用了大部分的CPU,它不会挂起。

在app.js上我有:

 var hostSchema = new mongoose.Schema({ ip: String, date: { type: Date, default: Date.now } }); var orderSchema = new mongoose.Schema({ name: String, metricCount: { impression: { type: Number, default: 0 }, clicks: { type: Number, default: 0 }, complete: { type: Number, default: 0 } }, impressionHosts: [hostSchema], clicksHosts: [hostSchema], completeHosts: [hostSchema] }); var Order = mongoose.model('order', orderSchema); var Host = mongoose.model('host', hostSchema); 

和快速获取方法:

 app.get('/pixel/:metric/:campaignName', function(req, res){ var campaignName = req.params.campaignName; var metrica = req.params.metric; Order.find({name: campaignName}, function(err, doc){ newMet = {}; newMet[metrica] = 1; var incomingHost = new Host({ip: req.ip}); if(doc.length<1){ insertNewElement(campaignName, newMet, metrica, incomingHost); }else { updateElement(doc[0], metrica, incomingHost); } }); res.end(pixel, 'binary'); }); 

当我评论“updateElement”函数时,node.js执行“完美”。 这里这些function:

 function updateElement(doc, metrica, incomingHost){ doc.metricCount[metrica]+=1; doc[metrica+'Hosts'].push(incomingHost); doc.save(function(err){ if(err){ console.log(err); } //console.log('Record Updated') }); } function insertNewElement(campaignName, newMet, metrica, incomingHost) { new Order({ name : campaignName, metricCount: newMet }).save(function(err, doc){ if (err) res.json(err); doc[metrica+'Hosts'].push(incomingHost); doc.save(function(err){ if(err){ console.log(err); } // console.log('new record added '+ doc.name); }); }); } 

我相信这个问题是在推新主机的时候存在的,因为有很多,虽然我不是mongoDB的专家,但是我不知道如何改进这个方法,如果这样做会导致问题。 由于mongo文档和研究,我的代码大部分都进​​行了调整。

如何更快地更新并避免nodejs上的内存错误?

谢谢!

当你用mongo创build一个文档时,它将一部分磁盘空间分配给文档,并且有足够的填充以容纳估计增长的文档。 如果文档大小超过了分配的空间,mongo需要移动并重新分配文档的新空间。 随着您的文档越来越多,这将会继续发生。

为了避免这种情况,您将需要预先分配空间。 您可以通过在文档中填充足够的数据,mongo将分配足够的空间以适应最大文档大小。

在你的情况下,当你第一次插入一个新的文档时,你会添加足够的主机子文档,以复制你的大文档。 插入该文档后,可以删除主机子文档并插入正确的logging。

现在,这并不完美。 Mongo不支持事务,因此在插入过程清理预分配的文档之前,可能会有一个更新触发文档。

同样对于mongo,请尽可能缩短字段名称。 无论何时使用,Mongo都会将整个字段名称存储为文档的一部分。 虽然这可能看起来不多,但它可以占据大型集合中的大量磁盘空间。