DynamoDB PutItem使用所有堆内存-NodeJS

问题描述 投票:0回答:1

我有一个超过一百万行的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,调整此值没有影响。

node.js amazon-web-services amazon-dynamodb
1个回答
0
投票

对于任何正在努力上网的人,并试图找出DynamoDB为什么要消耗所有堆内存的人,这里有一个github bug报告:https://github.com/aws/aws-sdk-js/issues/1777#issuecomment-339398912

[基本上,aws sdk只有50个套接字来发出http请求,如果所有套接字都被占用,则事件将排队,直到一个套接字可用为止。在处理数百万个请求时,这些套接字会立即被消耗掉,然后队列建立起来,直到炸毁堆为止。

所以,您如何解决这个问题?

  1. 增加堆大小
  2. 增加插槽数
  3. 控制正在排队的“事件”的数量

选项1和2是简单的解决方法,但没有扩展性。如果您正在做一件事,但它们可能会适合您的情况,但是如果您尝试构建可靠的解决方案,那么您将不会选择第3条。

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

现在,我可以将数百万个条目上载到dynamodb,而不必担心炸毁堆。

© www.soinside.com 2019 - 2024. All rights reserved.