亚马逊S3支持批量上传吗?我有一个任务,需要每晚上传约100K个文件,可达到1G的大小,但强烈偏向于小文件(90%的文件小于100字节,99%的文件长度小于1000字节)。
S3 API是否支持在单个HTTP调用中上传多个对象?
所有对象必须作为单独的对象在S3中可用。 我不能将它们放在其他地方(FTP等)或以另一种格式(数据库,EC2本地驱动器等)进行托管。这是我无法更改的外部要求。
亚马逊S3支持批量上传吗?我有一个任务,需要每晚上传约100K个文件,可达到1G的大小,但强烈偏向于小文件(90%的文件小于100字节,99%的文件长度小于1000字节)。
S3 API是否支持在单个HTTP调用中上传多个对象?
所有对象必须作为单独的对象在S3中可用。 我不能将它们放在其他地方(FTP等)或以另一种格式(数据库,EC2本地驱动器等)进行托管。这是我无法更改的外部要求。
S3 API是否支持在单个HTTP调用中上传多个对象?
不支持,S3 PUT操作每个HTTP请求只能上传一个对象。
您可以在需要与远程存储桶同步的计算机上安装S3工具,并运行以下命令:
s3cmd sync localdirectory s3://bucket/
然后,您可以将此命令放在脚本中并创建一个定时作业以每晚运行此命令。
这应该可以实现您想要的功能。
该工具基于MD5哈希和文件大小执行文件同步,因此冲突应该很少见(如果您确实希望如此,可以使用“ s3cmd put”命令强制盲目覆盖目标存储桶中的对象)。
编辑:还请确保阅读我链接的S3工具网站上的文档 - 根据您是否想要从存储桶中删除本地已删除的文件或忽略等情况,需要不同的标志。
是否可以将文件批量上传到Amazon S3?
是的*。
S3 API支持在单个HTTP调用中上传多个对象吗?
不支持。
Amazon S3 API不支持批量上传,但是awscli支持并发(并行)上传。从客户端的角度和带宽效率上看,这些选项应该表现得差不多。
────────────────────── time ────────────────────►
1. Serial
------------------
POST /resource
────────────────► POST /resource
payload_1 └───────────────► POST /resource
payload_2 └───────────────►
payload_3
2. Bulk
------------------
POST /bulk
┌────────────┐
│resources: │
│- payload_1 │
│- payload_2 ├──►
│- payload_3 │
└────────────┘
3. Concurrent
------------------
POST /resource
────────────────►
payload_1
POST /resource
────────────────►
payload_2
POST /resource
────────────────►
payload_3
文档提供了关于如何提高Amazon S3同步命令的传输性能的建议,其中之一是:
为了潜在地提高性能,您可以修改
max_concurrent_requests
的值。该值设置同时可发送到Amazon S3的请求数。默认值为10,您可以将其增加到更高的值。但是,请注意以下几点:
- 运行更多的线程会消耗您机器上的更多资源。必须确保您的计算机有足够的资源来支持您想要的最大并发请求数。
- 过多的并发请求可能会使系统不堪重负,从而导致连接超时或系统响应速度变慢。为避免AWS CLI的超时问题,您可以尝试将
--cli-read-timeout
值或--cli-connect-timeout
值设置为0。
一个设置max_concurrent_requests
并上传目录的脚本可能如下所示:
aws configure set s3.max_concurrent_requests 64
aws s3 cp local_path_from s3://remote_path_to --recursive
为了说明运行更多的线程会消耗更多的资源,我在一个运行aws-cli
容器中(使用procpath
)进行了小型测量,通过上传包含约550个HTML文件(总共约40 MiB,平均文件大小约为72 KiB)的目录到S3。下面的图表显示了上传aws
进程的CPU使用率、RSS和线程数。
除了大家所说的,如果你想让你的Java代码(而不是CLI)在无需将所有文件放入单个目录的情况下执行此操作,你可以创建要上传的文件列表,然后将该列表提供给AWS TransferManager的uploadFileList方法。
这里有一个全面的批处理解决方案,使用单个CommandPool::batch调用将文件从一个文件夹复制到另一个文件夹,尽管在底层它为每个文件运行executeAsync命令,因此不确定它是否算作单个API调用。
据我所知,您应该能够使用此方法复制数十万个文件,因为没有办法将批处理发送到AWS进行处理,但如果您将其托管在AWS实例上甚至在Lambda上运行,则其“技术上”在AWS上处理。
安装SDK:
composer require aws/aws-sdk-php
use Aws\ResultInterface;
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
use Aws\S3\Exception\DeleteMultipleObjectsException;
$bucket = 'my-bucket-name';
// Setup your credentials in the .aws folder
// See: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials_profiles.html
$s3 = new S3Client([
'profile' => 'default',
'region' => 'us-east-2',
'version' => 'latest'
]);
// Get all files in S3
$files = array();
try {
$results = $s3->getPaginator('ListObjects', [
'Bucket' => $bucket,
'Prefix' => 'existing-folder' // Folder within bucket, or remove this to get all files in the bucket
]);
foreach ($results as $result) {
foreach ($result['Contents'] as $object) {
$files[] = $object['Key'];
}
}
} catch (AwsException $e) {
error_log($e->getMessage());
}
if(count($files) > 0){
// Perform a batch of CopyObject operations.
$batch = [];
foreach ($files as $file) {
$batch[] = $s3->getCommand('CopyObject', array(
'Bucket' => $bucket,
'Key' => str_replace('existing-folder/', 'new-folder/', $file),
'CopySource' => $bucket . '/' . $file,
));
}
try {
$results = CommandPool::batch($s3, $batch);
// Check if all files were copied in order to safely delete the old directory
$count = 0;
foreach($results as $result) {
if ($result instanceof ResultInterface) {
$count++;
}
if ($result instanceof AwsException) {
}
}
if($count === count($files)){
// Delete old directory
try {
$s3->deleteMatchingObjects(
$bucket, // Bucket
'existing-folder' // Prefix, folder within bucket, as indicated above
);
} catch (DeleteMultipleObjectsException $exception) {
return false;
}
return true;
}
return false;
} catch (AwsException $e) {
return $e->getMessage();
}
}
如果你想使用Java程序来实现,可以这样做:
public void uploadFolder(String bucket, String path, boolean includeSubDirectories) {
File dir = new File(path);
MultipleFileUpload upload = transferManager.uploadDirectory(bucket, "", dir, includeSubDirectories);
try {
upload.waitForCompletion();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
AWSCredentials credentials = new BasicAWSCredentials(accessKey, token);
s3Client = new AmazonS3Client(credentials); // This is deprecated but you can create using standard beans provided by spring/aws
s3Client.setEndpoint("http://127.0.0.1:9000");//If you wish to connect to local S3 using minio etc...
TransferManager transferManager = TransferManagerBuilder.standard().withS3Client(s3Client).build();