文件上传到servlet优化

时间:2016-01-27 02:56:28

标签: spring spring-mvc file-upload

我有一个基于Spring的Web应用程序,有时需要将多个部分文件作为多部分文件发送和接收。上传文件时,通常会直接写入数据库。下载后,无需任何处理即可随时阅读和发送。在某些时候进行负载测试时,应用程序开始抛出OutOfMemoryErrors。为了解决这个问题,我不是将完整的多部分文件加载到内存中,而是在请求/响应输入/输出流和数据库中的blob之间直接读写。正如预期的那样,修复了OutOfMemoryErrors。但是,应用程序在低负载下执行速度会慢3-7倍。

我认为为了将整个多部分文件加载到内存并注入控制器,仍然需要通过相同的请求的输入流和底层套接字来读取它。 Spring如何加载相同客户端发送的相同文件,比直接读取它们快得多?

编辑:强调低负荷。一旦它运行足够长或足够高,负载性能将进一步恶化,因为(我猜)gc必须经常运行。那之前怎么样?

添加相关代码: 基本上这种类型的控制器

 public ResponseEntity<String> saveStuff(..., MultipartFile file){
    .... 
    dao.save(..., file.getBytes());
 }

替换为

 public ResponseEntity<String> saveStuff(..., HttpServletRequest request){
    .... 
    dao.save(..., request.getInputStream());
 }

在dao中,将输入流写入blob的部分是

try {
    byte[] bytesRead = new byte[4096];
    while (in.read(bytesRead, 0, bytesRead.length) != -1) {
        toBlob.write(bytesRead);
    }
} catch (IOException e) {
   e.printStackTrace();
} finally {
    try {
        in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        toBlob.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2 个答案:

答案 0 :(得分:1)

你的代码甚至不正确,所以为什么你担心它的性能还不清楚。试试这个:

int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

与您的不同,此版本正确写入最终的部分缓冲区。

关于性能,我会尝试使用更大的缓冲区大小,32k或更多。

答案 1 :(得分:0)

所以基本上整个问题都是过度思考一个简单的问题。它实际上不是关于读取请求的输入,而是将其写入数据库的速度很慢。基本上不是乱搞缓冲区和读/写字节而是所有需要发生的事情

statement.setBinaryStream(paramIndex, requestInputStream, contentLength);
//....execute statement and stuff....