java - 大文件下载导致超出 GC 开销限制
问题描述
我有两个服务,第一个是 frontend_service 和第二个 backend_service,我从 backend_service 获取大文件,并尝试使用 response.getBodyAsStream() 通过 frontend_service 转发给用户,但这会导致“java.lang.OutOfMemoryError:超出 GC 开销限制”前端服务。
backend_service 的代码:
`
public static Result downloadLargeFile(String filePath){
File file = new File(filePath);
InputStream inputStream = new FileInputStream(file);
return ok(inputStream);
}
`
frontend_service 的代码:
`
public static F.Promise<Result> downloadLargeFile(String filePath) {
//this will call backend_service downloadLargeFile method.
String backEndUrl = getBackEndUrl(filePath);
return getInputStream(backEndUrl);
}
`
`
public static Promise<Result> getInputStream(String url) {
return WS.url(url).get().map(
response -> {
InputStream inputStream = response.getBodyAsStream();
return ok(inputStream);
}
);
}
`
我通过从 inputStream 一次读取几个字节并在 frontend_service 中创建 tmp 文件并将 tmp 文件作为 frontend_service 的输出发送来尝试此处建议的解决方案。
`
public static Promise<Result> getInputStream(String url) {
return WS.url(url).get().map(
response -> {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
//write input stream to tmp file
final File tmpFile = new File("/tmp/tmp.txt");
outputStream = new FileOutputStream(tmpFile);
int read = 0;
byte[] buffer = new byte[500];
while((read = inputStream.read(buffer)) != -1){
outputStream.write(buffer, 0 , read);
}
return ok(tmpFile);
} catch (IOException e) {
e.printStackTrace();
return badRequest();
} finally {
if (inputStream != null) {inputStream.close();}
if (outputStream != null) {outputStream.close();}
}
}
);
`
上面的代码也抛出了 java.lang.OutOfMemoryError。我正在尝试 1 GB 文件。
解决方案
我没有“手下”的实现,所以我会写算法。
1. PlayAsyncHttpClient
使用WS
. 您需要获取它,或者按照https://www.playframework.com/documentation/2.3.x/JavaWS#Using-WSClient中的说明创建它
2.然后,你需要实现AsyncCompletionHandler
,就像在类的描述中一样https://static.javadoc.io/org.asynchttpclient/async-http-client/2.0.0/org/asynchttpclient/AsyncHttpClient.html
3、在类的onBodyPartReceived
方法中AsyncCompletionHandler
,需要将body部分推送到chunked play响应中。此处描述的更改响应:https ://www.playframework.com/documentation/2.3.x/JavaStream#Chunked-responses
附言
类似解决方案的讨论,但方向相反 - 通过“前端”(播放 2)服务流式上传到“后端”(亚马逊)服务: https ://groups.google.com/d/msg/asynchttpclient/EpNKLSG9ymM /BAGvwl0Wby8J