从AWS RDS(SQL Server)到通过lambda nodejs(流)的S3存储桶

时间:2019-03-19 16:41:59

标签: node.js amazon-s3 stream aws-lambda

尝试通过csv-stringify转换将一些SQL Server数据(aws rds)下载到S3存储桶时遇到了麻烦。

我在nodejs 8.10中使用了lambda函数

由于下载的记录可能是几百万条,因此我必须使用其他流*我将无法在内存中存储记录集。

所以我有一个SQL请求 req ,一个 stringifier 和一个名为 uplaod 的s3-up-streams流。

我也尝试了s3-stream,结果相同:当记录数超过200K时,我遇到了最大内存错误。

我添加了一些日志记录以尝试了解发生了什么,并发现问题是s3-upload-stream(与s3-stream相同)在关闭流之前不会发送 part ,将所有内容保存在内存中。

这是我从日志中得到的:

  

2019-03-19T16:09:31.995Z查询已执行
  2019-03-19T16:09:32.092Z S3缓冲设置为5242880 x 1
  2019-03-19T16:09:32.113Z流正在运行
  2019-03-19T16:09:37.933Z处理的记录:10000可用内存:70750208
  2019-03-19T16:09:40.494Z处理的记录:20000可用内存:64368640
  2019-03-19T16:09:43.492Z处理的记录:30000可用内存:78753792
  2019-03-19T16:09:45.652Z处理的记录:40000可用内存:75481088
  2019-03-19T16:09:47.952Z处理的记录:50000可用内存:72622080
  2019-03-19T16:09:50.853Z处理的记录:60000可用内存:68972544
  2019-03-19T16:09:53.013Z处理的记录:70000可用内存:67604480
  2019-03-19T16:09:55.193Z处理的记录:80000可用内存:64204800
  2019-03-19T16:09:57.933Z处理的记录:90000可用内存:80928768
  2019-03-19T16:10:00.152Z处理的记录:100000可用内存:79167488
  2019-03-19T16:10:02.392Z处理的记录:110000可用内存:76013568
  2019-03-19T16:10:05.292Z处理的记录:120000可用内存:73478144
  2019-03-19T16:10:07.572Z处理的记录:130000可用内存:73641984
  2019-03-19T16:10:10.852Z处理的记录:140000可用内存:72503296
  2019-03-19T16:10:14.053Z处理的记录:150000可用内存:69713920
  2019-03-19T16:10:14.074Z字符串化器已完成
  2019-03-19T16:10:16.012Z编写s3部分
  2019-03-19T16:10:16.013Z {ETag:'“ a4e3140f5d17fab9b3ccff9561a05730”',
    零件编号:1,
    大小:5242880,
    uploadSize:5242880}
  2019-03-19T16:10:16.204Z编写s3部分
  2019-03-19T16:10:16.204Z {ETag:'“ 30c90f1880190bea1fc9b5e1e7a1286d”',     零件号:2,
    尺寸:5530146,
    uploadSize:5530146}
  2019-03-19T16:10:16.401Z {ServerSideEncryption:'AES256',
    位置:“ https://someplaceinmys3bucket”,
    值区:“ mybucket”,
    密钥:“ foldername / lambdaTest.csv”,
    ETag:'“ 553d7927911f047633d04503f92a9281-2”“}
  END RequestId:   REPORT RequestId:持续时间:45686.58 ms内存大小:128 MB使用的最大内存:117 MB

如您所见,我每2.5秒可以下载大约10000条记录,但是只有在我关闭stringify之后,s3流才调用part事件。

这是我的代码设置:

req.stream = true; 
req.query(sql);    

if (__DEBUG) console.log("query executed");
upload = s3Stream.upload(s3params);

console.log("S3 Buffering is set to "+s3BufLen+" x "+s3ConcurrentBuffers);
upload.concurrentParts(s3ConcurrentBuffers); // limit to x buffers
upload.on('part', function (details) {
            if (__DEBUG){
                console.log("writing s3 part");
                console.log(details);
             }
 });

upload.on('uploaded', function (details) {
                    console.log(details);
                    mssql.close();
                    callback(null,details);
});

var stringifier = stringify(csvOptions);

stringifier.on('finish', function(){
                          if (__DEBUG) console.log("stringifier done");
                          upload.end();
                     });

stringifier.on('readable', function()
                          {
                            let row;
                            while(row = stringifier.read())
                            {
                               if (__DEBUG && (++processed % 10000 == 0)) console.log("Processed records : "+processed+
                                  " Available memory : "+ os.freemem());
                                upload.write(row); 
                            }
                          });

req.pipe(stringifier); //.pipe(upload);

我暂时“取消”上传流,并在处理程序中添加了stringifier.on以更好地调试过程。

我期望的是,每遇到5MB的块,就会调用上载流的 part 事件,而在关闭流之后显然会清除所有块。

请注意,我还强制将upload.concurrentParts(...)设置为1,无济于事。

更新:

我看到s3-upload-streams模块被认为已弃用,它建议改用s3.upload(来自AWS开发工具包),这确实改善了这一点-它使用的内存更少,但是并不能完全解决对我来说是问题,内存消耗仍然随着零件数量而增加。

这就是我修改代码的方式:

    var upload = new stream.PassThrough(), 
    s3options = {partSize: s3BufLen, queueSize: s3ConcurrentBuffers};

    s3params.Body = upload;

    s3.upload(s3params, s3options, function(err, data) {
              console.log(err, data);
              mssql.close();
              callback(err,data);
    });

    req.pipe(stringifier).pipe(upload);

我想念什么?

谢谢

0 个答案:

没有答案