【发布时间】:2013-09-08 02:37:19
【问题描述】:
我正在开发一个托管在 EC2 上的像素跟踪应用程序,它会在视频广告的每个请求上调用,因此它会跟踪它何时开始、完成以及是否进行了点击操作。我将 node.js 与 express 一起使用,因为我想尽可能快地响应和 mongoDB/Mongoose,因为它就像一个服务器日志结构。我几乎每毫秒都会收到请求。但是当将文档存储到集合中时,它几乎 100% 占用了大量的 CPU,最后 node.js 启动错误:
GET /pixel/impression/ad1 200 1ms
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory
我认为是猫鼬操作在我移除部件时占用了大部分 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);
以及快速get方法:
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 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 中缺少文档级锁定,整个数据库在写入时被锁定。您可以通过确保不需要在同一时间更新任何索引来加快此过程。
-
不,不是真的,我相信我只是“使用” _id: 默认情况下的索引。实际上,我认为这与搜索某些内容时缺少索引有关,但我认为(就像您一样)这将无济于事。也许 doc[metrica+'Hosts'].push(...) 有问题,因为这可能是一大堆文档。你怎么看?
-
如果您的文档不断增长,它可能会迫使它在磁盘上重新分配以防止其碎片化。我将在下面的答案中详细说明更多信息。
标签: node.js mongodb express amazon-ec2 mongoose