Source code: https://github.com/turingg/file-server/tree/gatling-issue
I am running some experiments with servlets and am using Gatling for load testing.
When I run my load test to upload a file that is about 500MB with more than 1 concurrent user using Gatling, most of the requests fail.
For example, for this load test:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class SyncUploadSimulation extends Simulation {
val httpConf = http.baseUrl("http://localhost:8080")
val scn = scenario("Upload files via sync endpoint")
.exec(http("Upload 1")
.post("/file-server/sync/upload")
.bodyPart(RawFileBodyPart(
"document",
"/path/to/500-mb-file.tar"
))
.check(status.is(200))
.check(jsonPath("$.status").is("Success"))
)
.pause(1)
setUp(scn.inject(atOnceUsers(2)))
.protocols(httpConf)
}
Tomcat fails with:
java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. java.io.EOFException: Unexpected EOF read on the socket
at org.apache.catalina.connector.Request.parseParts(Request.java:2915)
at org.apache.catalina.connector.Request.getParts(Request.java:2770)
at org.apache.catalina.connector.Request.getPart(Request.java:2939)
at org.apache.catalina.connector.RequestFacade.getPart(RequestFacade.java:1105)
at javax.servlet.http.HttpServletRequestWrapper.getPart(HttpServletRequestWrapper.java:374)
at xyz.behrang.fileserver.sync.SyncUploadServlet.isPartValid(SyncUploadServlet.java:71)
at xyz.behrang.fileserver.sync.SyncUploadServlet.doPostImpl(SyncUploadServlet.java:46)
at xyz.behrang.fileserver.sync.SyncUploadServlet.doPost(SyncUploadServlet.java:30)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:239)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:215)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.apache.tomcat.util.http.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. java.io.EOFException: Unexpected EOF read on the socket
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:298)
at org.apache.catalina.connector.Request.parseParts(Request.java:2868)
... 35 more
Caused by: org.apache.catalina.connector.ClientAbortException: java.io.EOFException: Unexpected EOF read on the socket
at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:340)
at org.apache.catalina.connector.InputBuffer.checkByteBufferEof(InputBuffer.java:632)
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:362)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:132)
at org.apache.tomcat.util.http.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:977)
at org.apache.tomcat.util.http.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:881)
at java.base/java.io.InputStream.read(InputStream.java:205)
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:98)
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:294)
... 36 more
Caused by: java.io.EOFException: Unexpected EOF read on the socket
at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:743)
at org.apache.coyote.http11.Http11InputBuffer.access$300(Http11InputBuffer.java:41)
at org.apache.coyote.http11.Http11InputBuffer$SocketInputBuffer.doRead(Http11InputBuffer.java:1070)
at org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:102)
at org.apache.coyote.http11.Http11InputBuffer.doRead(Http11InputBuffer.java:246)
at org.apache.coyote.Request.doRead(Request.java:551)
at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:336)
... 44 more
However a similar test using a framework other than Gatling, with 2 or even 100 concurrent requests, passes successfully without any issues:
#!/bin/bash
set -eu
START=$(date +%s)
echo "Start time: ${START}."
for i in {1..100}
do
curl --silent --connect-timeout 3000 --max-time 3000 \
-F document=@"/path/to/500-mb-file.tar" \
localhost:8080/file-server/sync/upload &
done
wait
END=$(date +%s)
echo "Start time: ${START}."
echo "End time : ${END}."
echo "Total time: ${END} - ${START} = $(expr ${END} - ${START})"
echo "Done."
Which outputs:
Start time: 1575208592.
{"status":"Success"}
...
{"status":"Success"}
Start time: 1575208592.
End time: 1575208688.
Total time: 1575208688 - 1575208592 = 96
Done.
Any ideas what is causing this?
I’ve attached TRACE level logs.
gatling.log (43.8 KB)