我需要一个servlet从Amazon S3服务器返回文件。只有服务器具有要访问的凭据,S3存储桶不是公共的。我无法改变。有人告诉我使用数据流,但是它们是如此之慢。
为了进行测试,我有一个带有缩略图的小proyect,当您单击它时,它会打开一个带有完整图像的新标签。 5mb的图像需要大约一分钟的时间加载。真慢

从S3读取并返回数据流的函数:

public void downloadDirectlyFromS3(String s3Path, String fileName, HttpServletResponse response) {
    AmazonS3 s3Client = new AmazonS3Client(new ProfileCredentialsProvider());
    s3Client.setEndpoint(S3ENDPOINT);

    S3Object s3object = s3Client.getObject(new GetObjectRequest(s3Path, fileName));

    byte[] buffer = new byte[5 * 1024 * 1024];

    try {
        InputStream input = s3object.getObjectContent();
        ServletOutputStream output = response.getOutputStream();
        for (int length = 0; (length = input.read(buffer)) > 0;) {
            output.write(buffer, 0, length);
        }
        output.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

最佳答案

有两点很突出,可能是造成问题的原因。

public void downloadDirectlyFromS3(String s3Path, String fileName, HttpServletResponse response) {
    AmazonS3 s3Client = new AmazonS3Client(new ProfileCredentialsProvider()); // 1. new client for each request
    s3Client.setEndpoint(S3ENDPOINT);

    S3Object s3object = s3Client.getObject(new GetObjectRequest(s3Path, fileName)); //may return null if not found

    byte[] buffer = new byte[5 * 1024 * 1024];

    try {
        InputStream input = s3object.getObjectContent(); // 2. input stream is never closed
        ServletOutputStream output = response.getOutputStream();
        for (int length = 0; (length = input.read(buffer)) > 0;) {
            output.write(buffer, 0, length);
        }
        output.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}


我要做的第一个更改是为整个应用程序创建一个客户端并重用它。这可能是造成您问题的主要原因。 AWS客户端被认为是线程安全的,并且可以同时被多个请求使用。客户端处理连接池和重用,这将有助于加快多个请求的速度。

第二个更改是正确关闭资源。 input永远不会关闭,output不会在异常时关闭。考虑使用try-with-resources。

try(InputStream input = s3object.getObjectContent(); ServletOutputStream output = response.getOutputStream();) {

} catch (FileNotFoundException e) {
    e.printStackTrace(); // never thrown. s3object will be null
} catch (IOException e) {
    e.printStackTrace(); // consider using a logger for exceptions
}


同样,根据javadocs,当未找到对象时,s3object将为null,因此您不必检查FileNotFoundException。

另一个考虑因素是端点似乎是硬编码的。如果应用程序在ec2实例上运行,并且您的开发机器配置正确,则只需使用defaultClient。

AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();


构建器将为您查找端点。

当您的应用程序关闭时,请考虑调用s3Client.shutdown()

有关更多信息,我发现this有用。

关于java - 从Amazon S3读取Servlet太慢,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38656627/

10-11 01:14