You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Java SDK S3TransferManager上传大文件如何避免全量读入内存?

问题描述

我正在开发一个应用,需从无法控制的外部网站下载大文件,再使用AWS Java SDK v2将其副本上传至S3存储桶(还有其他操作),S3TransferManager由Spring Batch注入。

下载及上传代码如下:

URL website = new URL("https://big_website_url");

HttpURLConnection huc = (HttpURLConnection)website.openConnection();

try(ReadableByteInputChannel rbc = Channels.newChannel(huc.getInputStream());
    FileOutputStream fos = new FileOutputStream("filename.zip"))) {
    fos.getChannel().transferFrom(rbc, 0, huc.getContentLengthLong());
}

huc.disconnect();


String uploadFileKey = "my/download/path/filename.zip";

UploadFileRequest uploadFileRequest = 
   UploadFileRequest.builder()
       .putObjectRequest(b -> b.bucket("mybucket").key(uploadFileKey))
       .addTransferListener(LoggingTransferListener.create())
       .source(Paths.get("filename.zip"))
       .build();

FileUpload fileUpload = s3TransferManager.uploadFile(uploadFileRequest);

文件大小可能超过900MB,我使用Spring Boot的Docker镜像插件生成在Kubernetes中运行的应用:

mvn spring-boot:boot-image

Spring Boot生成的镜像最大直接内存缓冲区大小为10MB,我虽可修改该值,但希望尽可能降低容器内存占用。

问题在于我看到SDK文档描述:

"File will be read entirely and may be read multiple times in the event of a retry."

担心S3TransferManager会将整个文件读入内存后再上传,在文件达900MB、容器内存限制为500MB的情况下,是否可让S3TransferManager分块读取文件上传,还是必须退回到低阶分片上传请求?


解决方案

不需要退回到低阶分片上传API,S3TransferManager针对本地文件的上传场景,默认支持自动分块上传,不会将整个文件加载到内存中,具体说明和配置如下:

  1. 默认分块行为说明
    当使用UploadFileRequest且源为本地文件时,SDK默认会在文件大小≥8MB时触发分块上传逻辑,每个分块会被单独读取并上传,内存中仅保留当前处理的分块数据,内存占用仅为单分块大小加上少量SDK开销,完全符合你500MB内存限制的要求。你看到的文档描述是针对从InputStream上传的场景,而非本地文件上传。

  2. 显式配置分块大小
    如果需要更精准控制内存占用,可以显式设置最小分块大小(S3要求分块大小最小为5MB,最后一块除外),示例代码如下:

UploadFileRequest uploadFileRequest = 
   UploadFileRequest.builder()
       .putObjectRequest(b -> b.bucket("mybucket").key(uploadFileKey))
       .addTransferListener(LoggingTransferListener.create())
       .source(Paths.get("filename.zip"))
       .minimumPartSize(5 * 1024 * 1024) // 设置为5MB分块
       .build();
  1. 可选优化:跳过本地文件直接上传
    如果你的业务逻辑不需要保留本地文件副本,可以直接从外部网站的输入流分块上传到S3,节省磁盘空间和IO开销,示例代码如下:
URL website = new URL("https://big_website_url");
HttpURLConnection huc = (HttpURLConnection)website.openConnection();

try (InputStream inputStream = huc.getInputStream()) {
    UploadRequest uploadRequest = UploadRequest.builder()
            .putObjectRequest(b -> b.bucket("mybucket").key(uploadFileKey))
            .addTransferListener(LoggingTransferListener.create())
            .requestBody(RequestBody.fromInputStream(inputStream, huc.getContentLengthLong()))
            .minimumPartSize(5 * 1024 * 1024)
            .build();
    s3TransferManager.upload(uploadRequest).waitForCompletion();
} finally {
    huc.disconnect();
}
  1. 直接内存配置说明
    当前Spring Boot镜像的10MB直接内存设置完全足够处理5MB分块的上传,无需调整该值,可保持容器内存占用最低。

内容的提问来源于stack exchange,提问作者Brad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 12:17:36