2

我正在开发一个托管在 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);

和快速获取方法:

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上的内存错误?

谢谢!

4

1 回答 1

0

当您在 mongo 中创建文档时,它会为文档分配一部分磁盘空间,并具有足够的填充以适应文档的估计增长。如果文档大小超过分配的空间,mongo 需要移动并为文档重新分配新空间。随着您的文档不断增长,这将继续发生。

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

在您的情况下,当您第一次插入新文档时,您将添加足够的主机子文档,以复制较大的文档。插入该文档后,您可以删除 hosts 子文档并插入正确的记录。

现在,这并不完美。Mongo 不支持事务,因此您可能会在插入过程清理预先分配的文档之前对文档进行更新。

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

于 2013-09-05T02:14:55.823 回答