是否可以批量上传到亚马逊s3?

时间:2013-02-24 08:53:42

标签: web-services amazon-web-services amazon-s3 cloud blob

亚马逊s3是否支持批量上传? 我有一份工作需要每晚上传~100K的文件,最高可达1G但是偏向于小文件(90%小于100字节,99%小于1000字节)。

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

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

7 个答案:

答案 0 :(得分:40)

或者,您可以使用同步命令通过AWS CLI tool上传S3。

  

aws s3 sync local_folder s3:// bucket-name

您可以使用此方法将文件批量上传到S3。

答案 1 :(得分:30)

  

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

不,the S3 PUT operation仅支持每个HTTP请求上传一个对象。

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

s3cmd sync localdirectory s3://bucket/

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

这应该做你想要的。

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

编辑:另外请确保您阅读了我为S3 Tools链接的网站上的文档 - 您是否希望从本地删除文件或忽略等文件所需的不同标志。

答案 2 :(得分:1)

要补充每个人所说的话,如果您希望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.File-java.util.List-

答案 3 :(得分: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();
    }
}

答案 4 :(得分:0)

一个文件(或文件的一部分)=一个HTTP请求,但Java API现在支持高效的多文件上载,而无需使用TransferManager

自行编写多线程

答案 5 :(得分:0)

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

答案 6 :(得分:0)

调查

<块引用>

是否可以批量上传到 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 命令​​行界面

how can I improve the transfer performance of the sync command for 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