我需要一个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/