java文件上传到s3-multipart是否应该加快速度?

h7wcgrx3  于 2021-08-20  发布在  Java
关注(0)|答案(2)|浏览(485)

我们使用Java8和AWSSDK以编程方式将文件上载到AWSS3。对于上传大文件(>100mb),我们了解到首选的方法是多部分上传。我们尝试过,但它似乎没有加快它,上传时间仍然几乎与不使用多部分上传相同。更糟糕的是,我们甚至遇到内存不足错误,称堆空间不足。
问题:
使用多部分上传真的应该加快上传速度吗?如果没有,为什么要使用它?
为什么使用多部分上传比不使用更快地消耗内存?它是否同时上传所有部分?
有关我们使用的代码,请参见下文:

private static void uploadFileToS3UsingBase64(String bucketName, String region, String accessKey, String secretKey,
        String fileBase64String, String s3ObjectKeyName) {

    byte[] bI = org.apache.commons.codec.binary.Base64.decodeBase64((fileBase64String.substring(fileBase64String.indexOf(",")+1)).getBytes());
    InputStream fis = new ByteArrayInputStream(bI);

    long start = System.currentTimeMillis();
    AmazonS3 s3Client = null;
    TransferManager tm = null;

    try {

        s3Client = AmazonS3ClientBuilder.standard().withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                .build();

        tm = TransferManagerBuilder.standard()
                  .withS3Client(s3Client)
                  .withMultipartUploadThreshold((long) (50* 1024 * 1025))
                  .build();

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setHeader(Headers.STORAGE_CLASS, StorageClass.Standard);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, s3ObjectKeyName,
                fis, metadata).withSSEAwsKeyManagementParams(new SSEAwsKeyManagementParams());

        Upload upload = tm.upload(putObjectRequest);

        // Optionally, wait for the upload to finish before continuing.
        upload.waitForCompletion();

        long end = System.currentTimeMillis();
        long duration = (end - start)/1000;

        // Log status
        System.out.println("Successul upload in S3 multipart. Duration = " + duration);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (s3Client != null)
            s3Client.shutdown();
        if (tm != null)
            tm.shutdownNow();
    }

}
eqzww0vc

eqzww0vc1#

如果同时上载多个部分,则使用multipart只能加快上载速度。
在您的代码中,您正在设置 withMultipartUploadThreshold . 如果您的上载大小大于该阈值,那么您应该观察单独部分的并发上载。如果不是,则只应使用一个上载连接。你的意思是你有>100MB的文件,而在你的代码中,你有5010241025=52480000字节作为多部分上传的阈值,所以该文件部分的并发上传应该已经发生了。
但是,如果您的上传吞吐量受到网络速度的限制,则吞吐量不会有任何增加。这可能是你没有观察到任何速度增加的原因。
使用multipart还有其他原因,因为出于容错原因也建议使用multipart。而且,它的最大大小比单个上载的大。
有关更多详细信息,请参阅文档:
多部分上载允许您将单个对象作为一组部分上载。每个部分都是对象数据的连续部分。您可以独立地以任何顺序上载这些对象部分。如果任何部分的传输失败,您可以在不影响其他部分的情况下重新传输该部分。上传对象的所有部分后,AmazonS3将组装这些部分并创建对象。通常,当对象大小达到100 MB时,应该考虑使用多部分上传而不是在单个操作中上载对象。
使用多部分上载具有以下优点:
提高吞吐量-您可以并行上载部件以提高吞吐量。
从任何网络问题中快速恢复-较小的部件尺寸可最大限度地减少因网络错误而重新启动失败上载的影响。
暂停并恢复对象上载-您可以随时间上载对象部分。启动多部分上传后,没有过期;您必须明确完成或停止多部分上载。
在知道最终对象大小之前开始上载-您可以在创建对象时上载对象。
我们建议您通过以下方式使用多部分上载:
如果要通过稳定的高带宽网络上载大型对象,请使用多部分上载,通过并行上载对象部分以实现多线程性能,从而最大限度地利用可用带宽。
如果您正在通过不稳定的网络进行上载,请使用多部分上载,以避免重新启动上载,从而提高对网络错误的恢复能力。使用多部分上载时,只需重试上载上载过程中中断的部分。您不需要从头开始重新上传对象。

xeufq47z

xeufq47z2#

eis的答案很好。尽管你仍然应该采取一些行动: String.getBytes(StandardCharsets.US_ASCII)ISO_8859_1 防止使用更昂贵的编码,如utf-8。如果平台编码为utf-16le,则数据甚至会损坏(0x00字节)。
标准java Base64 有一些可能工作的de-/编码器。它可以在字符串上工作。但是,请检查正确的处理方式(线端)。
try with resources在出现异常/内部返回时也会关闭。
这个 ByteArrayInputStream 没有关闭,哪种样式更好(更容易垃圾收集?)。
您可以将executorfactory设置为线程池工厂,以限制全局线程数。
所以

byte[] bI = Base64.getDecoder().decode(
        fileBase64String.substring(fileBase64String.indexOf(',') + 1));
try (InputStream fis = new ByteArrayInputStream(bI)) {
    ...
}

相关问题