【问题标题】:Heap memory error with bulkwrite in Mongoose and Node.jsMongoose 和 Node.js 中的 bulkwrite 堆内存错误
【发布时间】:2021-12-23 23:50:55
【问题描述】:

我正在为 bulkWrite 操作而苦苦挣扎。我正在处理 100,000 个数据。以下代码适用于 40k 数据。如果我尝试保存超过 50k 的数据,我会遇到内存问题。

我尝试了 insertMany(),20k 数据失败。 upsert 100,000 个数据的有效方法是什么?

代码:

async bulkInsertData(array) {
      const options = [];
      await sleep(60000);
      for (const item of array) {
        options.push({
          updateOne: {
            filter: { "id": item.id },
            update: {
              "$set": 
              {
                caseType : item.caseType,
                category : item.category
              }
            },
            upsert: true
          }
        })
      };
      await sleep(60000);
      const result = await this.dataModel.bulkWrite(options , { ordered: false })
      console.log(result)          
    }

错误

 <--- Last few GCs --->

[22:0x5f968d0]  1896003 ms: Mark-sweep 502.2 (519.2) -> 498.4 (518.9) MB, 435.5 / 0.0 ms  (average mu = 0.158, current mu = 0.051) allocation failure scavenge might not succeed

[22:0x5f968d0]  1896424 ms: Mark-sweep 502.4 (518.9) -> 498.7 (519.9) MB, 392.6 / 0.0 ms  (average mu = 0.117, current mu = 0.067) allocation failure scavenge might not succeed

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

【问题讨论】:

  • 尝试更新nodejs版本。
  • 我使用的是 Nest 8.0.0。此错误发生在使用 2x dyno 运行的 Heroku 中。我正在寻找改进代码的可能方法
  • 但是为什么要使用bulkWrite?我之前遇到过类似的问题,并通过使用 for 循环逐行插入来解决它

标签: node.js mongodb nestjs bulkinsert


【解决方案1】:

我不是 Javascript/Node js 专家,所以我下面的代码在语法上可能不正确,但我可以看到问题在于您试图同时在内存中保留数千个查询。相反,如果您一次只构建有限数量的查询(例如 500 个),执行更新,清除查询数组,然后处理接下来的 500 条记录,您就不会耗尽内存

async bulkInsertData(array) {
      var options = [];
      var result;

      await sleep(60000);
      for (const item of array) {
        options.push({
          updateOne: {
            filter: { "id": item.id },
            update: {
              "$set": 
              {
                caseType : item.caseType,
                category : item.category
              }
            },
            upsert: true
          }
        })
        
        if(options.length === 500) {
           result = await this.dataModel.bulkWrite(options , { ordered: false })
           console.log(result)
           options = [] // Clear queries array
        }
      };
      await sleep(60000);    

      // For the last batch
      if(options.length > 0) {
           result = await this.dataModel.bulkWrite(options , { ordered: false });
           console.log(result);
      }      
}

【讨论】:

  • 这段代码基本上一次只将一个元素推入选项数组,并且不会输入任何一个 if 条件。
【解决方案2】:

我认为这取决于您的情况。根据我的个人经验,我尝试了几种不同的方法。

  1. 只需通过设置--max-old-space-size=SIZE 来更新NodeJS 使用内存大小。您可以查阅文档https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes。您可以试错以找到合适的限制。
  2. 就像@devatherock 建议的那样,您应该尝试批量插入。
  3. 尝试使用 mongo-native 驱动程序 (https://mongodb.github.io/node-mongodb-native/) 而不是 mongoose。 mongoose 是很好的 ORM 工具,但内存大小会更大。如果要插入大量数据,请尝试使用原生驱动程序并直接插入数据库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-18
    • 2022-01-01
    • 2021-05-28
    • 2019-12-06
    • 1970-01-01
    • 2019-03-06
    • 2013-11-30
    • 2021-05-11
    相关资源
    最近更新 更多