内存不足导入大型数据集

时间:2016-01-29 18:14:49

标签: node.js promise bluebird knex.js

我有一个节点ETL脚本,可以在大约1000个1000个项目中导入大量记录(在100万以北的某个地方)。为此,它:

  1. 请求第一批。这提供了前1000个项目,并告诉我们需要导入的批次数和我们可用的记录总数。
  2. 导入第一批1000条记录。
  3. 迭代每个额外的批次并导入该批次中的记录。
  4. 问题是我处理了大约80个批次(少于10%!)后内存不足,我认为这是我编写代码的方法的问题。就像在幕后积累的东西一样,我已经失去了识别它的所有能力。这是基本代码:

    getBatch(1)
        .each(function(item, i, total) {  // always 1000 iterations
            return save(item);
        })
        .then(function() {
            // Return an array of batch numbers left to be imported
            // In this case, batches 2 through ~1000. The totalBatches value
            // is saved to an in-scope variable within the getFirstBatch()
            // function.
            return Array.from(new Array(totalBatches - 1).keys(), x => x + 2);
        })
        .each(function(batchNumber, i, batchCount) {  // Just over 1000 iterations
            return getBatch(batchNumber)
                .each(function(item, i, total) {  // Always 1000 iteractions until the last batch
                    return save(item);
                });
        })
        .tap(function(importedBatchNumbers) {  // Not even close to getting here
            // Do a few minor cleanup operations
        })
        .then(function(importedBatchNumbers) {
            // Summarize
            totalBatchesImported = importedBatchNumbers.length + 1;
    
            console.log('...');
        })
    

    也许有更好的方法来解决这个问题,我还没有考虑过?我正在使用bluebird库进行promises,使用Knex来处理数据库活动。

    在这一点上,我真正知道的是我甚至都不亲近。工作做得很好,但远不够。任何建议都将非常感谢。

1 个答案:

答案 0 :(得分:0)

您的示例似乎并未考虑任何类型的异步过程。正如我所知道的那样,一旦运行,它将立即尝试处理所有1000个批次,当它不能同时进行时(~80),它会被废弃。

在开始加载下一个批次之前,您需要确保每个批次实际上已完成处理。

使用Stream可以很好地处理像这样的大型数据集。

您还可以使用库chunk the data for you