我有一个在 kubernetes 上运行的应用程序(Springboot api),并且我有一个带有
cpu:200m
和 memory:8Gi
的单个实例。我的jvm参数是:_JAVA_OPTIONS: -Xmx7G -Xms7G
我的目标是将一个或多个大小在 30Mb 到 1Gb 之间的文件从一个 s3 存储桶复制到另一个具有预先签名的 url。
当我使用 1 GB 文件并行调用我的 api 超过 2 次时,出现
java.lang.OutOfMemoryError: Java heap space
错误。
这是我的代码:
public ResponseEntity<String> transferData(Config config) throws IOException {
var inputUrl = config.getInputdUrl();
var outputUrl = config.getOutputdUrl();
var uploadConnection = uploader.getUploadConnection(outputUrl);
try (var inputStream = downloader.getDownloadConnection(inputUrl);
var outputStream = uploadConnection.getOutputStream()) {
IOUtils.copyLarge(inputStream, outputStream);
var resp = uploadConnection.getResponseCode();
return ResponseEntity
.status(HttpStatus.OK)
.body("Transfer done with response:" + resp);
} catch (IOException ioe) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("An error occurred while transferring data : " + ioe);
}
}
getUploadConnection
返回HttpURLConnection
:
var connection = (HttpURLConnection) new URL(presignedUrl).openConnection();
connection.setDoOutput(true);
connection.setRequestMethod(PUT.toString());
return connection;
getDownloadConnection
返回一个 HttpURLConnection
输入流。
HttpURLConnection connection = (HttpURLConnection) new URL(presignedUrl).openConnection();
connection.setRequestMethod(GET.toString());
connection.setDoOutput(true);
return connection.getInputStream();
关于我的代码和配置,我认为对内存的影响不太重要,因为我流式传输文件并且没有将其完全放入内存中。
我错过了什么?
编辑1: 我添加了
setChunkedStreamingMode
所以现在我的 getUploadConnection
返回 :
var connection = (HttpURLConnection) new URL(url).openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setChunkedStreamingMode(-1);
connection.setRequestMethod(PUT.toString());
return connection;
但是我的 s3 存储桶出现
411
错误
在我的输出连接中设置
setFixedLengthStreamingMode
后,我能够传输更多文件,而不会出现Out of memory error java heap space
问题。
我的输出连接:
var connection = (HttpURLConnection) new URL(presignedUrl).openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("PUT");
connection.setFixedLengthStreamingMode(downloadConnection.getContentLengthLong());