I've created two sample applications for testing file upload, one with MVC and one with WebFlux (Spring Boot 2.4.0-M2 because they have implemented zero-copy non-blocking transferTo
in that version). I did not configure anything on the servers (Netty and Tomcat).
The WebFlux code:
public Mono<Void> uploadFile(Mono<FilePart> filePartMono) {
return filePartMono.flatMap(
filePart -> filePart.transferTo(
STORAGE_PATH.resolve(UUID.randomUUID().toString())
)
);
}
The MVC code:
public void uploadFile(MultipartFile multipartFile) throws IOException {
multipartFile.transferTo(
STORAGE_PATH.resolve(UUID.randomUUID().toString())
);
}
I've created two JMeter tests, one is testing one big file upload (2GB ISO), other is testing with 1000 threads using small files (1MB documents).
MVC file upload outperforms WebFlux around 10 times in speed, and never throws errors. WebFlux on the other hand sometimes never completes the file upload but does not throw exception either (some kind of deadlock?), or in other cases I get a no more space left on device error. I investigated the latter and it turned out that the files are duplicated/temporarly stored(?) in /tmp/spring-multipart
folder and that drive gets full fast. Even if the file upload manages to complete successfully, these files are not deleted. I couldn't find anything about this issue by Googling. (I also couldn't find where these files are written in Windows so I'm missing 30GB space right now. :))
As I've observed, MVC writes a dozen files at a time, while WebFlux writes little chunks to all. Should I publish on an other Scheduler to reduce the context switches or it will introduce an other bottleneck?
What am I missing here? What performance should I be expecting to be normal at all? On localhost I presumed (nearly) OS copy speed.
Edit: removed the publishOn(Schedulers.boundedElastic()) from the WebFlux code snippet.
Edit 2: I also tried to use FilePart
's content()
method to read the DataBuffers
, it filled up my /tmp
folder as well, but this time the temp files were in nio-file-upload
. Memory consumption was way more than MVC.