java - 在java servlet中流式传输大文件

标签 java java-io

我正在构建一个需要扩展的 Java 服务器。其中一个 servlet 将提供存储在 Amazon S3 中的图像。

最近在负载下,我的 VM 内存不足,这是在我添加代码来提供图像之后,所以我很确定流式传输更大的 servlet 响应是我的麻烦。

我的问题是:关于如何编写 java servlet 以在从数据库或其他云存储读取时将大型(>200k)响应流式传输回浏览器,是否有任何最佳实践?

我考虑过将文件写入本地临时驱动器,然后生成另一个线程来处理流式传输,以便可以重新使用 tomcat servlet 线程。这似乎是 io 很重。

如有任何想法,我们将不胜感激。谢谢。

最佳答案

如果可能,您不应将要提供的文件的全部内容存储在内存中。相反,获取数据的 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();

我同意 toby 的观点,您应该改为“将它们指向 S3 url”。

至于OOM异常,你确定它与提供图像数据有关吗?假设您的 JVM 有 256MB 的“额外”内存用于提供图像数据。在 Google 的帮助下,“256MB/200KB”= 1310。对于 2GB“额外”内存(如今这是一个非常合理的数量),可以同时支持超过 10,000 个客户端。即便如此,1300 个并发客户端也是一个相当大的数字。这是您遇到的负载类型吗?如果不是,您可能需要到别处寻找 OOM 异常的原因。

编辑 - 关于:

In this use case the images can contain sensitive data...

当我几周前阅读 S3 文档时,我注意到您可以生成可以附加到 S3 URL 的过期 key 。因此,您不必向公众开放 S3 上的文件。我对该技术的理解是:

  1. 初始 HTML 页面包含指向您的网络应用程序的下载链接
  2. 用户点击下载链接
  3. 您的网络应用会生成一个 S3 URL,其中包含一个在比方说 5 分钟后过期的 key 。
  4. 使用第 3 步中的 URL 向客户端发送 HTTP 重定向。
  5. 用户从 S3 下载文件。即使下载时间超过 5 分钟,此方法仍然有效 - 下载开始后,它可以继续完成。

关于java - 在java servlet中流式传输大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43457737/

相关文章:

java - new File ("...") 是否锁定文件?

java - 更新到7.7.0后,ElasticSearch在MacOS上不起作用

java - 无法访问 freemarker 模板中的 session 属性

java - 未处理的异常类型filenotfoundException,编译问题

java - 无法写入文件

java - 从 URI 的 PATH 读取文件

java - 有没有办法在 Java Web 中获得 "universal variable"?

java - 在 Java 类中具有 super() 和不具有 super() 函数调用的构造函数有什么区别

java - JNI 调用 API - NoClassDefFoundError (C/Java)