最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Node.js - Transfer Large Files Without Consuming A Lot of Memory - Stack Overflow

programmeradmin1浏览0评论

Motive : Transfer Files of around 10gb to 50gb from client to server using node

Problem : Consuming a lot of memory sometimes reaches around 6gb and system hangs

What I want is : my code should not use more than 200mb of ram..

What I Am Doing : I pause my stream when ram usage reaches 200 mb

Expected : That I am gonna pause streaming data when ram usage reaches 200 mb and will Resume it when usage es down.

What's happening : I pauses when usage is above 200 mb but it does not resumes cos even the script is pause the ram usage is not ming down.

Client.js

  var net = require('net'),
   fs = require('fs'),
  path = require('path');

  socket = new net.Socket();
  socket.connect(6000, 127.0.0.1);
  socket.on('connect',function(){

 // I am reading around 10 gb of file in chunks

 var readStream = fs.createReadStream("File Name", {highWaterMark: 16384});

  // Checking ram usage every second to ensure it does not consume more than 200 mb of ram, If i do not write this check it even uses 4gb+ ram for this much big file and hangs my node script.

  setInterval(function(){
    if(process.memoryUsage().rss > 209715200){
        // if ram consumtion is more that 200 mb
        console.log("Pause");
        global.gc();
        readStream.pause();
    }else{
        readStream.on('pause',function(){
          readStream.resume();
        });
    }
  },1000);

 readStream.on('data', function(chunk){

   console.log("Used Mem "+process.memoryUsage().rss);
   var head = new Buffer.from("FILE");
   var sizeHex = chunk.length.toString(16);
   while(sizeHex.length < 4){
     sizeHex = "0" + sizeHex;
   }
   var size = new Buffer.from(sizeHex);
   var delimiter = new Buffer.from("@");
   var pack = Buffer.concat([head, size, chunk, delimiter]);
     // sending data to server
     // This sending part start consuming ram 
     socket.write(pack,function(){
     });
 });

 readStream.on('close', function(){
   socket.end();
   global.gc();
 });


 });

Server.js

  var net = require('net'),
  fs = require('fs'),
  path = require('path');

  var server = net.createServer(function(socket){
    var packets = 0;
    var buffer = new Buffer.alloc(0);
// Receiving Data
    socket.on('data', function(chunk){
      buffer = Buffer.concat([buffer, chunk]);
    });


// when Client socket ends write file on server 
    socket.on('close', function(){

      var writeStream = fs.createWriteStream("New File Name");
      while(buffer.length){
        var head = buffer.slice(0, 4);

        if(head.toString() != "FILE"){
          console.log("ERROR!!!!");
          process.exit(1);
        }

        var sizeHex = buffer.slice(4, 8);
        var size = parseInt(sizeHex, 16);


        var content = buffer.slice(8, size + 8);
        var delimiter = buffer.slice(size + 8, size + 9);

        if(delimiter != "@"){
          console.log("wrong delimiter!!!");
          process.exit(1);
        }
        writeStream.write(content);
        buffer = buffer.slice(size + 9);
      }

      setTimeout(function(){
        writeStream.end();
      }, 2000);

    });   

  });

   server.listen(6000);

Ram Usage in system Monitor

  Before Running Above Script : 1.6gb of 6 gb 
  After Running Above Script : 1.8 gb of 6gb

Motive : Transfer Files of around 10gb to 50gb from client to server using node

Problem : Consuming a lot of memory sometimes reaches around 6gb and system hangs

What I want is : my code should not use more than 200mb of ram..

What I Am Doing : I pause my stream when ram usage reaches 200 mb

Expected : That I am gonna pause streaming data when ram usage reaches 200 mb and will Resume it when usage es down.

What's happening : I pauses when usage is above 200 mb but it does not resumes cos even the script is pause the ram usage is not ming down.

Client.js

  var net = require('net'),
   fs = require('fs'),
  path = require('path');

  socket = new net.Socket();
  socket.connect(6000, 127.0.0.1);
  socket.on('connect',function(){

 // I am reading around 10 gb of file in chunks

 var readStream = fs.createReadStream("File Name", {highWaterMark: 16384});

  // Checking ram usage every second to ensure it does not consume more than 200 mb of ram, If i do not write this check it even uses 4gb+ ram for this much big file and hangs my node script.

  setInterval(function(){
    if(process.memoryUsage().rss > 209715200){
        // if ram consumtion is more that 200 mb
        console.log("Pause");
        global.gc();
        readStream.pause();
    }else{
        readStream.on('pause',function(){
          readStream.resume();
        });
    }
  },1000);

 readStream.on('data', function(chunk){

   console.log("Used Mem "+process.memoryUsage().rss);
   var head = new Buffer.from("FILE");
   var sizeHex = chunk.length.toString(16);
   while(sizeHex.length < 4){
     sizeHex = "0" + sizeHex;
   }
   var size = new Buffer.from(sizeHex);
   var delimiter = new Buffer.from("@");
   var pack = Buffer.concat([head, size, chunk, delimiter]);
     // sending data to server
     // This sending part start consuming ram 
     socket.write(pack,function(){
     });
 });

 readStream.on('close', function(){
   socket.end();
   global.gc();
 });


 });

Server.js

  var net = require('net'),
  fs = require('fs'),
  path = require('path');

  var server = net.createServer(function(socket){
    var packets = 0;
    var buffer = new Buffer.alloc(0);
// Receiving Data
    socket.on('data', function(chunk){
      buffer = Buffer.concat([buffer, chunk]);
    });


// when Client socket ends write file on server 
    socket.on('close', function(){

      var writeStream = fs.createWriteStream("New File Name");
      while(buffer.length){
        var head = buffer.slice(0, 4);

        if(head.toString() != "FILE"){
          console.log("ERROR!!!!");
          process.exit(1);
        }

        var sizeHex = buffer.slice(4, 8);
        var size = parseInt(sizeHex, 16);


        var content = buffer.slice(8, size + 8);
        var delimiter = buffer.slice(size + 8, size + 9);

        if(delimiter != "@"){
          console.log("wrong delimiter!!!");
          process.exit(1);
        }
        writeStream.write(content);
        buffer = buffer.slice(size + 9);
      }

      setTimeout(function(){
        writeStream.end();
      }, 2000);

    });   

  });

   server.listen(6000);

Ram Usage in system Monitor

  Before Running Above Script : 1.6gb of 6 gb 
  After Running Above Script : 1.8 gb of 6gb
Share Improve this question edited Aug 22, 2018 at 19:52 m1ch4ls 3,43520 silver badges31 bronze badges asked Aug 22, 2018 at 8:16 Neeraj WaliaNeeraj Walia 2284 silver badges17 bronze badges 4
  • Have you tried unsetting pack after writing it to socket so gc can pick it up? Like: delete pack; global.gc(); – dkasipovic Commented Aug 22, 2018 at 9:12
  • 1 @DamirKasipovic Tried it But Still same issue – Neeraj Walia Commented Aug 22, 2018 at 9:39
  • What node.js version are you using? – m1ch4ls Commented Aug 22, 2018 at 11:32
  • I am Using node v10.6.0 @m1ch4ls – Neeraj Walia Commented Aug 22, 2018 at 18:17
Add a ment  | 

1 Answer 1

Reset to default 5

The problem is you are not waiting for socket.write to finish... The callback in socket.write is there to signal that writing has finished and you can send another chunk.

Instead of manually writing to socket use pipe or pipeline to manage the streaming for you.

This is my take:

client.js

const net = require('net');
const fs = require('fs');
const { pipeline } = require('stream');

const socket = new net.Socket();
socket.connect(6000, '127.0.0.1');
socket.on('connect', function () {
  const fileStream = fs.createReadStream('/dev/zero', { highWaterMark: 16384, end: 2 * 1024 * 1024 * 1024 }); // read 2GB of zeros, replace with real file
  console.log('New file transfer');

  pipeline(
    fileStream,
    socket,
    (error) => {
      if (error) { console.error(error) }
      console.log('File transfer done');
    }
  );
});

server.js

const net = require('net');
const fs = require('fs');
const { pipeline } = require('stream');

const server = net.createServer(function (socket) {
  const fileStream = fs.createWriteStream('/dev/null');
  console.log('New file transfer');

  pipeline(
    socket,
    fileStream,
    (error) => {
      if (error) { console.error(error) }
      console.log('File transfer done');
    }
  )
});

server.listen(6000);

From what I have tested it never exceeds 100MB in RAM and overall the code behaves reasonably - so no gc and memory checks are necessary.

The code above is using pipeline function that is available only in latest Node.js 10 - in case you use older Node use pump package that works the same way.

发布评论

评论列表(0)

  1. 暂无评论