尝试通过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);
我想念什么?
谢谢