2012-09-07 21 views
3

我使用下面的代碼循環插入1000000文件到mongodb,但我發現節點進程佔用大量內存,我的客戶端已經死亡。[Node.js]通過本機驅動程序循環插入1000000個文件到mongodb,爲什麼節點佔用大量內存?

db.collection("batch_insert", function (err, collection) { 
    if (!err) { 
     var count = 0; 
     for (var i = 0; i < 1000000; i++) { 
      collection.insert({hello:'world', ok:'OKOKOK'}, {safe:true, serializeFunctions:false}, function (err, result) { 
       count++; 
       if (1000000 == count) { 
        db.close(); 
       } 
      }); 
     } 
    } else { 
     console.log(err); 
    } 
}); 
+0

你知道這不是批量插入嗎? – soulcheck

+0

我不知道節點如何管理這個,但是你在這裏創建了100萬個閉包。這可能會有點沉重嗎? – Thilo

回答

3

與其他數據庫一樣,mongodb需要一些時間來處理請求。你向它投擲了一百萬個請求,並且由於你的代碼塊中沒有任何內容,這意味着在任何時候都有一大堆請求會在某個地方排隊(最有可能在多個地方,其中一些位於驅動程序的內部代碼,其他節點的事件循環內)。這需要超過一點點的記憶。

如果排隊沒有發生,你可以阻止或放棄一些請求。有沒有這樣的免費午餐。

+0

如果我正確理解了節點,就沒有後臺線程,所以*隊列中的所有*將在隊列開始處理之前排隊(或至少在第一個完成回調被觸發之前)。 – Thilo

+0

mongo驅動程序的編寫方式可以在處理請求時在內部執行一些異步操作。 – ebohlman

+0

好的。但是,在排隊循環完成之前,回調不會被執行(並且出列),對吧? – Thilo

8

您的for週期會阻止事件循環。並且它不能去nextTick並處理查詢結果,直到所有查詢發送到mongodb。您需要使用異步方式批量插入數據。 類似這樣的:

var mongo = require('mongodb'); 

var Inserter = function (collection) { 
    this.collection = collection; 
    this.data = []; 
    this.maxThreads = 6; 
    this.currentThreads = 0; 
    this.batchSize = 5000; 
    this.queue = 0; 
    this.inserted = 0; 
    this.startTime = Date.now(); 
}; 

Inserter.prototype.add = function(data) { 
    this.data.push(data); 
}; 

// Use force=true for last insert 
Inserter.prototype.insert = function(force) { 
    var that = this; 
    if (this.data.length >= this.batchSize || force) { 
     if (this.currentThreads >= this.maxThreads) { 
      this.queue++; 
      return; 
     } 
     this.currentThreads++; 
     console.log('Threads: ' + this.currentThreads); 
     this.collection.insert(this.data.splice(0, this.batchSize), {safe:true}, function() { 
      that.inserted += that.batchSize; 
      var currentTime = Date.now(); 
      var workTime = Math.round((currentTime - that.startTime)/1000) 
      console.log('Speed: ' + that.inserted/workTime + ' per sec'); 
      that.currentThreads--; 
      if (that.queue > 0) { 
       that.queue--; 
       that.insert(); 
      } 
     }); 
    } 
}; 

var db = new mongo.Db('test', new mongo.Server('localhost', 27017, {}), {native_parser:false}); 
db.open(function(err, db) { 
    db.collection('test', function(err, collection) { 
     var inserter = new Inserter(collection); 
     setInterval(function() { 
      for (var i = 0; i < 5000; i++) { 
       inserter.add({test:'test'}); 
      } 
      inserter.insert(); 
     }, 0); 
    }); 
}); 
+1

我不能滿足這個答案。 – StuR

+0

我有一個稍微不同的問題,但您的評論指出我在正確的方向。感謝名單! –

+0

這種方法存在巨大的內存泄漏。通過只插入2000個條目,我的內存使用量猛增到1 GB。 – Angelin

相關問題