76

amazon s3 支持批量上传吗?我有一份工作需要每晚上传约 100K 的文件,这些文件最大可达 1G,但强烈倾向于小文件(90% 小于 100 字节,99% 小于 1000 字节)。

s3 API 是否支持在单个 HTTP 调用中上传多个对象?

所有对象都必须在 S3 中作为单个对象可用。我无法在其他任何地方(FTP 等)或其他格式(数据库、EC2 本地驱动器等)托管它们。这是我无法改变的外部要求。

4

7 回答 7

46

或者,您可以使用sync命令通过AWS CLI 工具上传 S3 。

aws s3 同步local_folder s3://bucket-name

您可以使用此方法非常快速地将文件批量上传到 S3。

于 2014-06-16T19:07:50.807 回答
40

s3 API 是否支持在单个 HTTP 调用中上传多个对象?

不可以,S3 PUT 操作仅支持每个 HTTP 请求上传一个对象。

您可以在要与远程存储桶同步的机器上安装S3 工具,然后运行以下命令:

s3cmd sync localdirectory s3://bucket/

然后,您可以将此命令放在脚本中并创建一个计划作业以每晚运行此命令。

这应该做你想要的。

该工具基于 MD5 哈希和文件大小执行文件同步,因此冲突应该很少(如果你真的想要你可以使用“s3cmd put”命令来强制盲覆盖目标存储桶中的对象)。

编辑:还要确保您阅读了我为 S3 工具链接的站点上的文档 - 您是否希望本地删除的文件从存储桶中删除或忽略等需要不同的标志。

于 2013-02-24T10:40:22.110 回答
3

为了补充大家所说的,如果您希望您的 java 代码(而不是 CLI)执行此操作而不必将所有文件放在一个目录中,您可以创建一个要上传的文件列表,然后提供该文件列表到 AWS TransferManager 的 uploadFileList 方法。

https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/TransferManager.html#uploadFileList-java.lang.String-java.lang.String-java.io。文件-java.util.List-

于 2018-10-04T22:21:59.363 回答
3

民意调查

是否可以批量上传到 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

AWS 命令​​行界面

有关如何提高 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 和线程数。

aws s3 cp --recursive, max_concurrent_requests=64

于 2021-07-08T17:41:50.830 回答
1

如果你想使用 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();
    }
}

如果您想测试,创建 s3client 和传输管理器以连接到本地 S3,如下所示:

    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();
于 2018-08-17T09:33:24.090 回答
1

这是一个全面的批处理解决方案,它使用一次CommandPool::batch调用将文件从一个文件夹复制到另一个文件夹,尽管它在后台为每个文件运行一个executeAsync命令,但不确定它是否算作一次 API 调用。据我了解,您应该能够使用此方法复制数十万个文件,因为无法将批处理发送到 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();
    }
}
于 2020-02-20T02:41:10.833 回答
0

一个文件(或文件的一部分)= 一个 HTTP 请求,但 Java API 现在支持高效的多文件上传,而无需您自己编写多线程,通过使用TransferManager

于 2017-07-05T20:55:53.280 回答