Node.js 使用所有堆内存的DynamoDB PutItem-NodeJS

Node.js 使用所有堆内存的DynamoDB PutItem-NodeJS,node.js,amazon-web-services,amazon-dynamodb,Node.js,Amazon Web Services,Amazon Dynamodb,我有一个超过一百万行的csv,我想把所有的行导入DynamoDB。我能够很好地循环csv,但是,当我尝试在这些行上调用DynamoDB PutItem时,在大约18k次调用后,我的堆内存用完了 我不明白为什么要使用这个内存,也不明白我怎样才能避开这个问题。这是我的密码: let insertIntoDynamoDB = async () => { const file = './file.csv'; let index = 0; const readLine = create

我有一个超过一百万行的csv,我想把所有的行导入DynamoDB。我能够很好地循环csv,但是,当我尝试在这些行上调用DynamoDB PutItem时,在大约18k次调用后,我的堆内存用完了

我不明白为什么要使用这个内存,也不明白我怎样才能避开这个问题。这是我的密码:

let insertIntoDynamoDB = async () => {
  const file = './file.csv';
  let index = 0;

  const readLine = createInterface({
    input: createReadStream(file),
    crlfDelay: Infinity
  });

  readLine.on('line', async (line) => {
    let record = parse(`${line}`, {
      delimiter: ',',
      skip_empty_lines: true,
      skip_lines_with_empty_values: false
    });

    await dynamodb.putItem({
      Item: {
        "Id": {
          S: record[0][2]
        },
        "newId": {
          S: record[0][0]
        }
      },
      TableName: "My-Table-Name"
    }).promise();

    index++;
    if (index % 1000 === 0) {
      console.log(index);
    }
  });
  // halts process until all lines have been processed
  await once(readLine, 'close');

  console.log('FINAL: ' + index);
}

如果我注释掉Dynamodb调用,我可以很好地浏览文件并阅读每一行。内存使用从何而来?我的DynamoDB写吞吐量是500,调整这个值没有影响

对于那些不愿意通过互联网查找DynamoDB消耗所有堆内存的原因的人,这里有一个github bug报告:

基本上,aws sdk只有50个套接字来发出http请求,如果所有套接字都已使用,则事件将排队,直到套接字可用为止。当处理数以百万计的请求时,这些套接字会立即被占用,然后队列会不断增加,直到堆被炸毁

那么,你是如何避免这种情况的呢

  • 增加堆大小
  • 增加插座的数量
  • 控制排队的“事件”数量
  • 选项1和2是简单的解决方法,但不可缩放。它们可能适用于您的场景,如果您正在做一件一次性的事情,但是如果您正在尝试构建一个健壮的解决方案,那么您将不会选择第三个

    要执行第3步,我确定最大堆大小,并将其除以我认为“事件”在内存中的大小。例如:我假设dynamodb的updateItem事件是100000字节。我的堆大小是4GB,因此4000000000B/100000 B=40000个事件。但是,我只使用了这么多事件中的50%在堆上为节点应用程序可能正在执行的其他进程留出空间。此百分比可以根据您的喜好降低/增加。一旦有了事件数量,我就从csv中读取一行并使用一个事件,当事件完成后,我将事件释放回池中。如果没有可用的事件,则暂停csv的输入流,直到事件可用为止


    <>现在我可以上传数百万条到DyDoDB,不用担心炸毁堆。

    你可能想考虑使用<代码> BatchWriteItem <代码>。它不能回答内存的去向问题,但是它更适合大量的put。至少它会减少您发出的请求数量。我可以尝试
    BatchWriteItem
    ,也许它不会泄漏内存。我没有这样做的唯一原因是它一次只能有25个项目,所以它仍然可以线性扩展。事实上比这更糟糕。它只能有25个项目,但最多只能写入16MB。不管怎样,您都需要检查响应中的
    未处理项
    ,查看是否需要再次调用。因此,这无疑增加了复杂性。听起来这是值得调查/报告的。在github repo上提交一份bug报告,希望能有所收获。你能告诉我“事件何时完成”是什么意思吗?我使用的是C#await,因此我假设对“PutItemAsync”的每个调用都在下一个调用尝试之前完成。但是,我也遇到了内存不足错误。对我来说,它调用了大约110000次PutItemAsync,内存使用量上升到3.2GB,然后我得到了“System.OutOfMemoryException”。我试着偶尔加入“线程。睡眠”来给电话一个结束的机会,但似乎没有什么不同。好吧,我似乎已经解决了这个紧迫的问题。我在调用方法中使用了C#Task.Run(…).Wait(),但我发现这似乎并不是真正的等待!现在我正在使用C#wait all down调用树,内存稳定在1.1GB。我不知道为什么会出现这种差异。从描述来看,它听起来像。Wait应该比Wait更阻塞,而不是更少。。