节点

时间:2018-02-28 19:06:19

标签: node.js mongodb mongoose memory-leaks

我的节点应用程序面临内存问题。拿了一些堆转储并看到很多mongo对象被保存在内存中,导致节点应用程序耗尽内存。

我的应用程序有以下设置。

MongoDB 3.4.13

Mongoose 4.11.10(尝试过4.13.11和5.0.7)

节点8.9.4

config.js

const clientUID = require('./env').clientUID;

module.exports = {
  // Secret key for JWT signing and encryption
  secret: 'mysecret',
  // Database connection information
  database: `mongodb://localhost:27017/app_${clientUID}`,
  // Setting port for server
  port: process.env.PORT || 3000,
}

我在应用程序中有几个模型。每个模型都按以下方式定义(仅列出其中一个模型):

模型/ card.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const CardSchema = new Schema({
  name: {
    type: String,
    unique: true,
    required: true
  },
    macId: {
    type: String,
    unique: true,
    required: true
  },
  cardTypeId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'CardType',
    required: true
  },
},
{
  timestamps: true
});

module.exports = mongoose.model('Card', CardSchema);

在应用程序中,我需要模型并执行以下操作:

const Card = require('./models/card');
...require other models

const config = require('./config');
mongoose.connect(config.database);

function fetchCardByMacId(macId) {
  return Card.findOne({ macId }).lean().exec();
}

function updateTrackerByMacId(macId, x, y, nodeId) {
  const data = {x, y, lastNodeId: nodeId};
  fetchCardByMacId(macId)
    .then(card => {
      Tracker.findOneAndUpdate({ cardId: card._id }, data, { upsert: true, new: true }).exec((error, tracker) => {
        if (error) {
          return console.log('update tracker error', error);
        }
        TrackerHistory.findOne({ trackerId: tracker._id }).exec((err, trackerHistory) => {
          if (err) {
            return console.log('fetch trackerHistory error', err);
          }
          if (trackerHistory) {
            trackerHistory.trackers.push({ x, y, timestamp: moment().format(), nodeId });
            TrackerHistory.findOneAndUpdate({_id: trackerHistory._id},trackerHistory,(er, trackerHis) => {
              if (er) {
                return console.log('trackerHistory change update error', er);
              }
            })
          } else {
            const trackerHistoryNew = new TrackerHistory({
              trackerId: tracker._id,
              trackers: [{ x, y, timestamp: moment().format(), nodeId }]
            });
            trackerHistoryNew.save((er, trackerHis) => {
              if (er) {
                return console.log('trackerHistory create error', er);
              }
            });
          }
        });
      });
    }).catch(error => {
      console.log('updateTrackerByMacId error', error);
    });
}

像这样,还有许多其他功能可以读取和更新数据。

我每5秒钟就会收到需要插入数据库的新数据(不超过几百kbs),并且一些旧的数据库数据也会根据这些新数据进行更新(看起来像是相当简单的db操作... .read,操作和更新)。

我从index.js中生成了2个子进程,这些进程负责处理这些新数据并根据业务逻辑更新数据库。当使用事件侦听器在index.js中接收到新数据时,我将其发送到子进程1以插入/更新数据库。子进程2在10s计时器上运行以读取此更新数据,然后对数据库进行进一步更新。

在我的本地macbook pro上运行它是没有问题的(使用的日志堆内存永远不会超过40-50mb)。当我将它加载到DO Ubuntu 16.04服务器(4GB / 2 CPU)时,我面临内存问题。在达到进程的内存阈值(~1.5gb)后,子进程正在退出,这对我来说似乎很奇怪。 我还尝试使用docker容器执行此操作并查看相同的结果。在Mac上运行没有问题,但在服务器上它正在吃掉内存。 生成heapdumps会在堆中显示很多mongo对象。

我想帮助理解我在这里做错了什么,以及mongo在服务器上占用这么多内存的问题是什么。

1 个答案:

答案 0 :(得分:0)

因此TrackerHistory集合的建模方式存在很大问题。 TrackerHistory有一个数组,每次必须将一个新对象添加到数组中时,整个TrackerHistory对象都被加载到内存中,并且在更新实时数据的给定频率下,内存膨胀的速度比gc&#更快。 39; d

通过删除新集合中的跟踪器数组并向TrackerHistory添加外键引用来修复它。

帮助我确定此问题的参考文章。

https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1