我正在构建一个需要扩展的java服务器.其中一个servlet将提供存储在Amazon S3中的图像.
最近在加载时,我的虚拟机内存耗尽了,之后我添加了代码来提供图像,所以我很确定流式传输更大的servlet响应会导致我的麻烦.
我的问题是:在从数据库或其他云存储中读取时,如何编写java servlet以将大型(> 200k)响应流回浏览器,是否有任何最佳实践?
我已经考虑将文件写入本地临时驱动器,然后生成另一个线程来处理流,以便可以重用tomcat servlet线程.这似乎很重要.
任何想法将不胜感激.谢谢.
Joh*_*eff 55
如果可能,您不应存储要在内存中提供的文件的全部内容.相反,为数据获取InputStream,并将数据复制到Servlet OutputStream中.例如:
ServletOutputStream out = response.getOutputStream();
InputStream in = [ code to get source input stream ];
String mimeType = [ code to get mimetype of data to be served ];
byte[] bytes = new byte[FILEBUFFERSIZE];
int bytesRead;
response.setContentType(mimeType);
while ((bytesRead = in.read(bytes)) != -1) {
out.write(bytes, 0, bytesRead);
}
// do the following in a finally block:
in.close();
out.close();
Run Code Online (Sandbox Code Playgroud)
我同意toby,你应该"将它们指向S3网址".
至于OOM例外,你确定它与提供图像数据有关吗?假设你的JVM有256MB的"额外"内存用于提供图像数据.在Google的帮助下,"256MB/200KB"= 1310.对于2GB"额外"内存(这些天非常合理的数量),可以支持超过10,000个并发客户端.即便如此,1300个同步客户端数量也相当大.这是您遇到的负载类型吗?如果没有,您可能需要查看其他地方的OOM异常原因.
编辑 - 关于:
在这个用例中,图像可以包含敏感数据......
几周前,当我阅读S3文档时,我注意到您可以生成可以附加到S3 URL的时间过期密钥.因此,您不必向公众开放S3上的文件.我对该技术的理解是:
bla*_*ese 11
我已经看到很多代码,比如john-vasilef(当前接受的)答案,一个紧密的while循环从一个流中读取块并将它们写入另一个流.
我所提出的论点是反对不必要的代码重复,支持使用Apache的IOUtils.如果您已经在其他地方使用它,或者您正在使用的其他库或框架已经依赖它,那么它就是一条已知且经过充分测试的单行.
在下面的代码中,我将一个对象从Amazon S3流式传输到servlet中的客户端.
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
InputStream in = null;
OutputStream out = null;
try {
in = object.getObjectContent();
out = response.getOutputStream();
IOUtils.copy(in, out);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
Run Code Online (Sandbox Code Playgroud)
6条明确定义的模式与适当的流关闭看起来非常稳固.
| 归档时间: |
|
| 查看次数: |
76294 次 |
| 最近记录: |