nodejs:从文件读取并存储到db,限制最大并发数据库操作

时间:2014-08-02 18:14:46

标签: javascript node.js asynchronous concurrency

我有一个CSV文件,我正在以流的形式阅读,并使用转换转换为JSON,然后将每行异步存储到数据库。

问题是从文件读取速度很快,因此会导致非常大量的并发异步数据库操作,导致应用程序停止运行。

我想限制应用程序,以便在任何给定时间内最多有N个未完成的数据库操作正在进行中。

这是我的_transform函数的基本核心:

parser._transform = function(data, encoding, done) {
    //push data rows
    var tick = this._parseRow(data);

    //Store tick
    db.set(tick.date, tick, function(err, result) {
      console.log(result);
      if(err) throw err;
    });

    this.push(tick);
    done();
};

我看了几个选项,但这些似乎是最好的候选人:

  • 使用async api'forEachLimit'
    • 我在这里看到的问题是,在我的流转换中,我只在发布操作时对一个对象(文件中的行)进行操作。
    • 由于尺寸
    • ,读取整个文件是不可行的
  • 使用7.2.3节中所述的异步,并行,并发有限解决方案:
    • http://book.mixu.net/node/ch7.html
    • 这里的问题是在达到“限制”的情况下该怎么做。
    • 旋转或使用setTimeout似乎耗尽了所有预定的时间并阻止了我的数据库回调,这应该减少正在启动的“正在运行”的计数器。

这是我对'并发限制解决方案'的初步尝试:

var limit = 100;
var running = 0;

parser._transform = function(data, encoding, done) {
  //push data rows
  var tick = this._parseRow(data);

  this.push(tick);
  //Store tick to db
  if (running < limit) {
    console.log("limit not reached, scheduling set");
    running++;
    cb.set(tick.date, tick, function(err, result) {
      running--;
      console.log("running is:" + running);
      console.log(result);
      if(err) throw err;
    });
  } else {
    console.log("max limit reached, sleeping");
    setTimeout(this._transform(data, encoding, done),1000);
  }
  done();
};

本周我才开始使用node.js,所以我不清楚解决这个问题的正确模型是什么。

注意:我知道的一些事情是,如果使用后一种模式,至少应该是指数退避,并且应该有一些“最大退避”系统,所以不要吹掉掉话堆。尽管如此,试图在这里保持简单。

2 个答案:

答案 0 :(得分:2)

并发限制解决方案选项是我要采用的方法,但我不是自己实现,而是使用async模块。具体来说,是queue方法。

类似的东西:

var dbQueue = async.queue(function(tick, callback) {
    db.set(tick.date, tick, function(err, result) {
        console.log(result);
        callback(err, result);
    });
}, 3); // the last arg (3) is the concurrency level; tweak as needed

parser._transform = function(data, encoding, done) {
    //push data rows
    var tick = this._parseRow(data);

    dbQueue.push(tick);

    this.push(tick);
    done();
};

这会将您的数据库操作限制为3次。此外,您可以将队列的saturatedempty事件用于您的信息流pause / resume,以便在资源使用方面更加有限(如果您正在阅读非常大的文件,那将会很棒。这看起来像是:

dbQueue.saturated = function() {
    parser.pause();
}

dbQueue.empty = function() {
    parser.resume();
}

答案 1 :(得分:1)

数据库限于在任何给定时间同时进行一次磁盘写入。考虑到这一点,任何并行写入都会降低整个操作的速度。 如果文件足够小,请尝试将其全部读入内存,然后在一次操作中将其写入数据库。否则将其拆分为大块,然后一个接一个地查询它们。