我建立一个java服务器,需要规模。一个servlet会服务的图像存储在亚马逊S3。

最近在载荷下,我跑出来的记忆在我的虚拟机和它的后我加入代码服务的图像所以我敢肯定,大流servlet的答复是引起我的麻烦。

我的问题是:是否有任何最佳实践中如何码a java servlet流大(>达到200)应回到当浏览器读取的数据库或其他云存储?

我已经考虑编写的文件以一本地临时驱动和随后产生的另外一个线程,以处理流,以便tomcat servlet线可以重新使用。这似乎喜欢将它io重。

任何想法,将不胜感激。谢谢。

有帮助吗?

解决方案

当可能的,你不应该商店的全部内容的一个文件服务在存储器。相反,获取一个输入流的数据,并将数据复制到Servlet使用的输出流在件。例如:

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

我同意托比,你应该,而不是"点他们到S3网址。"

作为OOM例外,你肯定它已经做的与提供服务的图像数据?我们说您JVM有256MB的"额外的"存储器的使用提供图像数据。与谷歌的帮助下,"256MB/200KB"=1310.为2GB"额外的"存储器(这些天一个非常合理数量)10 000多同时进行的客户可能的支持。即便如此,1300同时客户是一个很大的数字。这是负荷类型你经验丰富?如果不是,你可能需要看看其它地方的原因OOM例外。

编辑有关:

在这种使用情况的图像可以包含敏感数据的...

当我读通过的S3文件的几个星期前,我注意到,你可以产生时间到期键,可以连接到S3的网址。所以,你将不会拥有打开文件上S3给公众。我的理解技术是:

  1. 初始HTML网页已经下载链接到你的网络应用程序
  2. 用户点击链接下载
  3. 你的网络应用程序生成S3网址包括一个关键的,到期,可以说,5分钟。
  4. 发送HTTP重定向到客户的网址从第3步。
  5. 用户下载的文件自S3。这一工作,即使下载时间超过5分钟-一旦开始下载它可以继续通过完成。

其他提示

为什么你不只是指他们的S3url?把一个人从S3,然后流它通过自己的服务器到我击败的目的使用S3,这是卸载的带宽,并处理的提供服务的图像亚马逊。

我见过很多的代码就像约翰-vasilef的(目前被接受的)的答案,一个紧密的同时,环读块是从一个流和写作他们向其他流。

参数中我想提出的是反对不必要的重复代码,有利于使用Apache IOUtils.如果你已经在使用它在其他地方,或者,如果另一个图书馆或框架你使用已经取决于它,它是一个单一的线,是已知的以及进行测试。

在下面的代码,我流的一个目的是从亚马逊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);
}

6线的一个明确的模式以适当的流关闭,似乎相当稳固。

我同意强与这两个toby和约翰Vasileff--S3是伟大的关闭装载大媒体对象如果你能容忍相关的问题。(一个实例自己的程序确实,对于10-1000MB通过使用智能手机或平板电脑的许和MP4s.) E.g.:没有部分的请求(byte范围头),虽然。一个具有处理这个"手工",偶尔下来的时间,等等。

如果这不是一个选项,约翰代码看起来很好。我发现一个字节缓冲区的2k FILEBUFFERSIZE是最有效的在microbench标记。另一种选择可能是一个共享FileChannel.(FileChannels是线的安全。)

这就是说,我也添加这一猜测是什么导致了记忆的错误是一个典型最优化的错误。你将会提高成功的机会通过工作与硬指标。

  1. 地方-XX:+HeapDumpOnOutOfMemoryError到你JVM启动的参数,只是在情况下
  2. 采取使用jmap在运行JVM(jmap-组织 <pid>)下载
  3. 合同的指标(jmap-组织了提出,或有jhat看看你的堆转储)。它很可能是你的记忆是来自某个地方出人意料的。

当然,还有其他的工具,但jmap&jhat来Java5+'出的盒子'

我已经考虑编写的文件以一本地临时驱动和随后产生的另外一个线程,以处理流,以便tomcat servlet线可以重新使用。这似乎喜欢将它io重。

啊,我不认为你不能这样做。甚至如果你可以的,这听起来可疑。在tomcat线管理的连接需要在控制。如果你遇到线饥饿然后增加数量的可用螺纹。/conf/server.xml.再次,指标的方法以检测此--不仅仅是猜测。

问题:你是不是也运行在EC2?什么是你tomcat的JVM开始参数?

托比是正确的,你应该是指直到S3,如果可以的话。如果你不能,问题是有点含糊不清给予准确的答复:你有多大的java堆?有多少流是打开同时当你的记忆?
你有多大的读写/缓冲溶液(8K是良好的)?
你正在读8K从流,然后编写8k的输出,对吧?你是不是想阅读完整的图像,从S3,缓冲存储器,然后送的整个事情?

如果您使用的是8K的缓冲区,可以有1000并发流会在~8Megs堆空间,所以你肯定是在做的事情是错误的。...

顺便说一句,我并没有选择8K在稀薄的空气,它是默认的大小插座缓冲区,发送更多的数据,说1Meg,你会被阻挡在tcp/ip堆保持大量的存储器。

你要检查两件事情:

  • 是你关闭的流?非常重要的
  • 也许你流连接的"免费"。流不大,但是许多多的流在同一时间可以偷所有你的记忆。创建一个游泳池,以便不能有一定数量的流行在同一时间

另外什么建议约翰,你应该多次冲洗出流。根据你的网的容器,这是可能的,它的缓存的部分或者甚至所有的输出,并刷新这一次(例如,计算出的内容的长标题)。会烧伤相当多的存储器。

如果你可以结构你的文件,因此,静态的文件都是单独的和在他们自己的斗,今天最快的性能可能可以通过使用亚马逊S3CDN 配置媒体播放器.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top