大文件下载导致超出GC开销限制

时间:2019-04-19 19:26:19

标签: java playframework playframework-2.3

我有两个服务,第一个是frontend_service和第二个backend_service,我正在从backend_service获取大文件,并尝试使用以下命令通过frontend_service转发给用户 response.getBodyAsStream(),但这会导致frontend_service中出现“ java.lang.OutOfMemoryError:超出了GC开销限制”。

后端服务代码:

`

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);
                    }
            );
}

`

我尝试了建议here的解决方案,方法是一次从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 个答案:

答案 0 :(得分:0)

我没有“手”的实现,因此我将编写算法。

1。播放使用AsyncHttpClient下的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方法中,您需要将主体部分推送到分块播放响应。此处描述的虚假响应:https://www.playframework.com/documentation/2.3.x/JavaStream#Chunked-responses

P.S。

关于类似解决方案的讨论,但方向相反-通过“前端”(播放2)服务将流上传到“后端”(亚马逊)服务: https://groups.google.com/d/msg/asynchttpclient/EpNKLSG9ymM/BAGvwl0Wby8J