我有一个应用,需要上传超过100,000 files
(每个1MB
)到S3 Bucket
。我知道S3有api用于上传一个大文件,但是想知道他们是否有api用于上传大量文件。
我目前正在使用putObject
并尝试upload
api将我的文件上传到S3。问题是上传时间太长(浏览器超时后完成)并使用大量内存(超过512MB
允许限制)。
保存文件的代码:
saveFile: async (fileUrl, data) => {
await s3.putObject({
Bucket: bucket,
Key: fileUrl,
Body: JSON.stringify(data)
}).promise();
},
在另一个地方,我把saveFile
放在这样的循环中:
for (let file of files) {
await saveFile(file.url, file.data);
}
我搜索了解决方案并发现stream
可能有助于减少内存需求,但我想知道时间有什么不同吗?如果是的话,我该如何实现呢?感谢。
答案 0 :(得分:3)
我通常更喜欢使用managed upload API而不是putObject方法。它处理具有多重上传内容的大型文件,并且它支持流(您不能使用带有putObject的流,因为该API需要总文件大小)。
例如,来自Node:
const fs = require('fs');
const AWS = require('aws-sdk');
const s3 = new AWS.S3({});
s3.upload({
Bucket: 'xxx',
Key: 'fileName.png',
Body: fs.createReadStream('/home/bar/Desktop/fileName.png')
}).promise(); // or callback
这可能会解决您与内存相关的问题,但可能不会加快上传速度。
for
循环的问题在于它会一个接一个地串行上传对象。相反,您可以使用await Promise.all([/* your list*/].map(/* ... */))
,它将并行执行所有上传 - 但是 - 100,000到目前为止是一个太大的数字。
我建议使用像async这样的库,它有很多有用的方法来处理异步操作组。
例如,您可以使用cargo
或queue
方法,您的代码如下所示:
const PARALLEL_UPLOADS = 10;
const q = async.queue((task, callback) => {
s3.upload({
Bucket: 'xxx',
Key: task.dest,
Body: fs.createReadStream(task.src)
}, callback)
}, PARALLEL_UPLOADS);
q.drain = function() {
console.log('all items have been processed');
};
q.push([
{ src: 'image1.png', dest: 'images/image1.png' },
{ src: 'image2.png', dest: 'images/image2.png' },
]);
这将同时上传所有文件,最多10个项目。
希望这有帮助,
答案 1 :(得分:0)
const AWS = require('aws-sdk');
const fs = require('graceful-fs'); // from node.js
const path = require('path'); // from node.js
const queue = require('async-promise-queue');
const s3 = new AWS.S3();
const pushS3 = (srcFolderPath, destFolderPath) => {
const uploadPromise = [];
console.log(`Pushing ${srcFolderPath} to S3`);
const files = fs.readdirSync(srcFolderPath);
if (!files || files.length === 0) throw new Error(`provided folder '${srcFolderPath}' is empty or does not exist.`);
// for each file in the directory
for (const fileName of files) {
// get the full path of the file
const filePath = path.join(srcFolderPath, fileName);
// ignore if directory
if (fs.lstatSync(filePath).isDirectory()) {
continue;
}
uploadPromise.push({
src: filePath,
dest: `${destFolderPath}${fileName}`,
});
}
const worker = queue.async.asyncify(task => s3.upload({
Bucket: AWS_BUCKET,
Key: task.dest,
Body: fs.createReadStream(task.src),
}).promise());
return queue(worker, uploadPromise, 10000);
};
pushS3('sourcePath', 'destinationS3Path')
.then(()=>{console.log('Sucessfully Transferred to S3');})
.catch((err)=>{console.error(err);})
保证上述Simone Lusenti解决方案的实现。就我而言,我有50000+个奇数文件。我试图将这些文件从AWS ECS放入S3。我之前有2个错误。通过EMFILE too many files open
模块,通过graceful-fs
模块和AWS ECS中的Missing Credentials Error
解决了async-promise-queue
错误。