У меня есть веб-приложение на основе Spring, которое иногда нужно отправлять и получать потенциально большие документы в виде файлов с несколькими частями. Когда файлы загружаются, они обычно записываются прямо в базу данных. При загрузке всегда считываются и отправляются с любой обработкой. При тестировании нагрузки в какой-то момент приложение начинает бросать OutOfMemoryErrors. Чтобы решить эту проблему, вместо того, чтобы загружать полный многокомпонентный файл в память, я читаю и пишу прямо между потоками запроса/ответа в/из потока и блобом в db. Как и ожидалось, это фиксировало OutOfMemoryErrors. Тем не менее, тогда приложение работает в 3-7 раз медленнее при низких нагрузках.Загрузка файла в оптимизацию сервлетов
Я бы подумал, что для загрузки всего файла с несколькими частями в память и ввода в контроллер его все равно нужно читать через входной поток и базовый сокет того же запроса. Как Spring может загружать те же самые файлы, отправленные одним и тем же клиентом, что намного быстрее, чем их прямое чтение?
Редактировать: акцент делается на низких нагрузках. После того, как он будет работать достаточно долго или с достаточно высокой нагрузкой, будет еще больше ухудшаться, потому что (Im guessing) gc должен работать довольно много постоянно. А что раньше?
добавив соответствующий код: в основном это контроллеры типа
public ResponseEntity<String> saveStuff(..., MultipartFile file){
....
dao.save(..., file.getBytes());
}
были заменены
public ResponseEntity<String> saveStuff(..., HttpServletRequest request){
....
dao.save(..., request.getInputStream());
}
и в дао той части, которая записывает входной поток в сгустка является
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();
}
}
Оставьте свой код. Основной проблемой будет размер буфера чтения. Чтение всей загрузки в память сначала добавляет латентность, а также тратит пространство, поэтому оно не должно быть быстрее, чем правильно написанный цикл с использованием разумного размера буфера. – EJP
уверен. добавлен соответствующий код. – aiguy
Вы отключили разбор партирования, т. Е. Удалили «MultipartResolver»? Кроме того, https://commons.apache.org/proper/commons-fileupload/streaming.html объясняет, как выполнять загрузку потоковых файлов с помощью файла commons-fileupload. «InputStream» в вашем случае - это не то же самое, что и «MultipartFile», поэтому не уверен, действительно ли вы написали правильный материал в базу данных ... Также интересно, что такое 'toBlob'? –