Hi, I face an issue with the NIO2 protocol. When I increase the request rate to more than 500 requests per second it starts failing with:
06-Oct-2020 09:18:19.964 FINE [https-jsse-nio2-8080-exec-6] org.apache.coyote.http2.Http2UpgradeHandler.init Connection [1], State [NEW] 06-Oct-2020 09:18:19.978 FINE [https-jsse-nio2-8080-exec-6] org.apache.coyote.http2.Http2AsyncParser$FrameCompletionHandler.failed Connection [1], Stream [0], Frame type [null], Error java.io.EOFException at org.apache.tomcat.util.net.SecureNio2Channel$2.completed(SecureNio2Channel.java:1005) at org.apache.tomcat.util.net.SecureNio2Channel$2.completed(SecureNio2Channel.java:1001) at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127) at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:158) at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:568) at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:276) at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297) at org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:1126) at org.apache.tomcat.util.net.Nio2Endpoint$Nio2SocketWrapper$Nio2OperationState.run(Nio2Endpoint.java:1025) at org.apache.tomcat.util.net.SocketWrapperBase$VectoredIOCompletionHandler.completed(SocketWrapperBase.java:1100) at org.apache.tomcat.util.net.SocketWrapperBase$VectoredIOCompletionHandler.completed(SocketWrapperBase.java:1054) at org.apache.tomcat.util.net.SecureNio2Channel$2.completed(SecureNio2Channel.java:1112) at org.apache.tomcat.util.net.SecureNio2Channel$2.completed(SecureNio2Channel.java:1001) at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127) at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:158) at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:568) at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:276) at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297) at org.apache.tomcat.util.net.SecureNio2Channel$2.completed(SecureNio2Channel.java:1038) at org.apache.tomcat.util.net.SecureNio2Channel$2.completed(SecureNio2Channel.java:1001) at org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:1124) at org.apache.tomcat.util.net.Nio2Endpoint$Nio2SocketWrapper$Nio2OperationState.run(Nio2Endpoint.java:1025) at org.apache.tomcat.util.net.Nio2Endpoint$Nio2SocketWrapper$Nio2OperationState.start(Nio2Endpoint.java:1004) at org.apache.tomcat.util.net.SocketWrapperBase.vectoredOperation(SocketWrapperBase.java:1450) at org.apache.tomcat.util.net.SocketWrapperBase.read(SocketWrapperBase.java:1293) at org.apache.tomcat.util.net.SocketWrapperBase.read(SocketWrapperBase.java:1265) at org.apache.coyote.http2.Http2AsyncParser.readConnectionPreface(Http2AsyncParser.java:55) at org.apache.coyote.http2.Http2UpgradeHandler.init(Http2UpgradeHandler.java:241) at org.apache.coyote.http2.Http2AsyncUpgradeHandler.init(Http2AsyncUpgradeHandler.java:40) at org.apache.coyote.http2.Http2UpgradeHandler.upgradeDispatch(Http2UpgradeHandler.java:316) at org.apache.coyote.http2.Http2AsyncUpgradeHandler.upgradeDispatch(Http2AsyncUpgradeHandler.java:40) at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:59) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) at org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1679) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.net.AbstractEndpoint.processSocket(AbstractEndpoint.java:1104) at org.apache.tomcat.util.net.SecureNio2Channel$HandshakeReadCompletionHandler.completed(SecureNio2Channel.java:99) at org.apache.tomcat.util.net.SecureNio2Channel$HandshakeReadCompletionHandler.completed(SecureNio2Channel.java:92) at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127) at java.base/sun.nio.ch.Invoker$2.run(Invoker.java:219) at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:832) 06-Oct-2020 09:18:19.980 FINE [https-jsse-nio2-8080-exec-6] org.apache.coyote.http2.Http2UpgradeHandler.upgradeDispatch Entry, Connection [1], SocketStatus [ERROR] If I just change the protocol to org.apache.coyote.http11.Http11NioProtocol then everything is OK. To reproduce: 1) git clone https://github.com/martin-g/http2-server-perf-tests.git 2) cd java/tomcat 3) mvn package 4) java -Dtomcat.http2=true -Dtomcat.protocol=org.apache.coyote.http11.Http11Nio2Protocol -Djava.security.egd=file:/dev/./urandom -jar target/tomcat-embedded*.jar The Vegeta <https://github.com/tsenart/vegeta> command is: echo -e '{"method": "GET", "url": "https://localhost:8080/testbed/plaintext"}' | vegeta attack -format=json -http2 -rate=0 -max-workers=128 -insecure -duration=5s | vegeta encode > /tmp/http2.json; and vegeta report -type=json /tmp/http2.json | jq . { "latencies": { "total": 827683197623, "mean": 5747799983, "50th": 6261543134, "90th": 6307893296, "95th": 6311484598, "99th": 7733411962, "max": 30000471023, "min": 28510451 }, "bytes_in": { "total": 180, "mean": 1.25 }, "bytes_out": { "total": 0, "mean": 0 }, "earliest": "2020-10-06T09:18:19.5182854+03:00", "latest": "2020-10-06T09:18:25.304404661+03:00", "end": "2020-10-06T09:18:55.304875684+03:00", "duration": 5786119261, "wait": 30000471023, "requests": 144, "rate": 24.887146894914306, "throughput": 0.4191514162416983, "success": 0.10416666666666667, "status_codes": { "0": 129, "200": 15 }, "errors": [ "Get \"https://localhost:8080/testbed/plaintext\": unexpected EOF", "unexpected EOF", "Get \"https://localhost:8080/testbed/plaintext\": net/http: request canceled (Client.Timeout exceeded while awaiting headers)" ] } Here I use '-rate=0' for unlimited/maximum rate, but it starts failing somewhere around 500: -rate=500/1s Martin