node.js - 在 Node.js 中保存大型文档时,MongoDB-mongoose 高 CPU 使用率

标签 node.js mongodb express amazon-ec2 mongoose

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

我认为当我移除部件时, 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);

以及express 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 中创建文档时,它会为文档分配一部分磁盘空间,并有足够的填充来适应文档的估计增长。如果文档大小超过分配的空间,mongo需要移动并为文档重新分配新的空间。随着您的文档不断增长,这种情况将会不断发生。

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

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

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

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

关于node.js - 在 Node.js 中保存大型文档时,MongoDB-mongoose 高 CPU 使用率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18616359/

相关文章:

node.js - 与 simple-peer (WebRTC) 的自动连接

javascript - 在sequelize where查询中使用OR语句

angularjs - 部署在云服务器上时使用 localhost 地址进行 $http.get 请求

javascript - Electron 架构 API 调用

mongodb - Symfony2 - 文档选择列表和 MongoDB

mongodb - mongo文件和gridfs文件关系

javascript - 来自 AngularJS 和查询字符串的 Restful API 调用

javascript - MongoDB : how to put conditional for multiple optional value

javascript - 使用带有非常简单脚本的 Node 发送后无法设置 header

node.js - MEAN 堆栈中的验证......?