【问题标题】:Running node js export in google cloud function在谷歌云功能中运行节点js导出
【发布时间】:2020-04-05 07:06:27
【问题描述】:

我们需要导出一个 zip 文件,其中包含大量数据(几 GB)。 zip 存档需要包含大约 50-100 个 indesign 文件(每个大约 100mb)和一些其他较小的文件。我们尝试使用谷歌云功能来实现它(成本更低等)。该功能通过配置文件触发,该文件上传到存储桶中。配置文件包含需要将哪些文件放入 zip 中的所有信息。不幸的是,总是达到 2gb 的内存限制,所以函数永远不会成功。

我们尝试了不同的方法: 第一个解决方案是循环文件,创建下载它们的承诺,在循环完成后,我们尝试一次解决所有承诺。 (文件通过流直接下载到文件中)。 第二次尝试是在 for 循环中等待每次下载,但再次达到内存限制。

所以我的问题是: 为什么node js不清除流?似乎节点将每个流文件保存在内存中并最终崩溃。我已经尝试按照此处的建议将 readStream 和 writeStream 设置为 null:

How to prevent memory leaks in node.js?

但没有变化。

注意:我们从来没有达到这一点,所有文件都被下载以创建 zip 文件。在第一个文件之后它总是失败。

见下方代码sn-ps:

// first try via promises all:
const promises = []
for (const file of files) {
    promises.push(downloadIndesignToExternal(file, 'xxx', dir));
}

await Promise.all(promises)


// second try via await every step (not performant in terms of execution time, but we wanted to know if memory limit is also reached:
for (const file of files) {
    await downloadIndesignToExternal(file, 'xxx', dir);
}


// code to download indesign file
function downloadIndesignToExternal(activeId, externalId, dir) {
  return new Promise((resolve, reject) => {
    let readStream = storage.bucket(INDESIGN_BUCKET).file(`${activeId}.indd`).createReadStream()
    let writeStream = fs.createWriteStream(`${dir}/${externalId}.indd`);
    readStream.pipe(writeStream);
    writeStream.on('finish', () => {
      resolve();
    });
    writeStream.on('error', (err) => {
      reject('Could not write file');
    })
  })
}

【问题讨论】:

  • 这里的dir究竟是什么?
  • 这是一个通过 os.tmpdir() 生成的目录。代码本身可以在我们的开发平台上运行,但只有小文件。在暂存(真实数据)时,我们达到了 2gb 内存限制。

标签: node.js garbage-collection google-cloud-functions google-cloud-storage


【解决方案1】:

对于任何感兴趣的人: 我们通过将文件流式传输到 zip 并将其直接流式传输到谷歌云存储来使其工作。现在内存使用量大约为 150-300mb,所以这对我们来说非常有效。

【讨论】:

    【解决方案2】:

    了解 /tmp (os.tmpdir()) 是 memory-based filesystem in Cloud Functions 很重要。当您将文件下载到 /tmp 时,它会占用内存,就像您将文件保存到内存中的缓冲区一样。

    如果您的函数需要的内存超出为函数配置的内存,那么 Cloud Functions 可能不是解决此问题的最佳解决方案。

    如果您仍想使用 Cloud Functions,则必须找到一种将输入文件直接流式传输到输出文件的方法,而无需在函数中保存任何中间状态。我确信这是可能的,但您可能需要为此编写大量额外的代码。

    【讨论】:

    • 有道理!我认为在这种情况下它对我们不起作用,因为我们想将 zip 文件上传到存储桶中。谢谢!
    • 您当然可以在内存中输入和输出 zip。我看到npm中有模块可以做到。
    猜你喜欢
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 2017-11-14
    • 2019-01-19
    • 2022-12-17
    • 2019-06-07
    • 2020-10-03
    • 2019-05-14
    相关资源
    最近更新 更多