在流中使用节点请求或axios来下载和解压缩文件,是否无法按预期处理背压?

Dev*_*Hod 5 javascript zlib request node.js axios

我们有一个大约6 GB的大文件,需要将其解压缩为64 GB大小(OS映像),我们需要使用http下载该文件。我们正在使用节点的请求库或axios。使用以下代码即时下载和解压缩文件(管道):

 const downloadUsingHttp = (downloadUrl, destinationPath) => {enter code here
      return new Promise((resolve, reject) => {
        const unpackedPathWriteStream = fs.createWriteStream(destinationPath);

        let totalDownloadSize = 64023257088;
        let downloadedSize = 0;
        let lastProgressSent = 0;

        axios({
          method: 'get',
          url: downloadUrl,
          responseType: 'stream',
          auth: {
            username: 'user',
            password: 'pass'
          },
            withCredentials: true
         }).then(function (response) {
            response.data
              .on('data', chunk => {
                if (totalDownloadSize === 0) {
                  return;
                }
                downloadedSize += chunk.length;
                const progress = Math.floor((downloadedSize / totalDownloadSize) * 100);

                if (progress % 5 !== 0) {
                  return;
                }

                if (lastProgressSent === progress) {
                  return;
                }

                lastProgressSent = progress;
                console.log('Copy progress ', progress + ' %')
              })
              .pipe(zlib.createUnzip())
              .pipe(unpackedPathWriteStream)

        }).catch((err) => {
           console.log(err.message)
        });

        unpackedPathWriteStream
          .on('error', err => {
            console.log(err);
            reject(err);
          }).on('end', () => {
            resolve();
          })
   })
};

downloadUsingHttp(
  'https://example.com/storage/file.raw.gz',
  '/data/downloaded-and-unziped.raw'
);
Run Code Online (Sandbox Code Playgroud)

我们正在运行此代码的机器具有2 GB的RAM。运行此代码时,出现的问题是计算机内存不足,进度约15%,节点应用程序崩溃。有时甚至整个计算机都变得无响应,需要重新启动。

因此,在这种情况下,似乎对流执行的.pipe()反压处理不起作用。例如,当不通过(使用请求或axios库)通过http下载文件,而是通过可读和可写流下载文件时,使用管道方法即时执行复制和解压缩的相同操作是有效的,并且不会浪费内存。

另外,重要的是要提到此问题仅在本地网络(本地开发环境)中执行http下载时才会出现。

任何帮助将被申请。

更新资料

我们尝试将数据流限制为100 KB / s,这似乎在没有增加RAM内存使用的情况下起作用。当更改为1 MB / s时,使用率增加,最终应用程序停止运行。我们已经使用stream-throttle库进行了尝试。

Tho*_*mas 0

我对管道没有太多经验,但是如何将文件分块加载并一次将它们送入管道呢?然后加载下一个块。因此管道一次只需处理几 MB 的数据。

我想象这样的事情:

const downloadUsingHttp = (downloadUrl, destinationPath, chunkSize = 10<<20) => {
  const writeStream = fs.createWriteStream(destinationPath);
  const unzip = zlib.createUnzip();

  const auth = {
    username: 'user',
    password: 'pass'
  };

  const nextChunk = () => axios({
      method: 'get',
      url: downloadUrl,
      responseType: 'stream',
      auth: auth,
      withCredentials: true,
      headers: {
        Range: `bytes=${offset}-${(offset += chunkSize)}`
      }
    }).then(downThePipe);

  const downThePipe = response => {
    console.log("progress %i%%   ( %i / %i bytes )", offset / length * 100, offset, length);
    response.data.pipe(unzip).pipe(writeStream);

    return offset < length ? nextChunk() : null;
  };

  let offset = 0, length;
  return axios({
    method: "HEAD",
    url: downloadUrl,
    auth: auth,
    withCredentials: true,
  }).then(response => {
    length = response.headers["Content-Length"];
    return nextChunk();
  });
};



downloadUsingHttp(
  'https://example.com/storage/file.raw.gz',
  '/data/downloaded-and-unziped.raw'
);
Run Code Online (Sandbox Code Playgroud)

也许,如果下载仍然太快,您可能希望延迟加载,nextChunk()直到pipe()工作完成后。但再说一遍,我使用这些管道已经有一段时间了。