我有一个基于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();
}
}
答案 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....