Peter,
On 4/9/21 06:53, Peter Chamberlain wrote:
Hello,
I've been trying to understand the behaviour of tomcat when handling
internal redirects. I'm testing using tomcat 9.0.38. I'm testing using
jdk8 1.8.0_265. My main test cases have been 2 forwards to the same
servlet, and then a response. Or 2 redirects to the same servlet and
then a response. Servlet as follows:
@WebServlet(loadOnStartup = 1, value = "/")
public class ConnectorLimitServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse
resp) throws IOException, ServletException {
int number = Integer.parseInt(req.getParameter("number"));
// Fake some work done at each stage of processing
try { Thread.sleep(500); } catch (InterruptedException e) {}
resp.setContentType("text/plain");
if (number <= 1) {
resp.getWriter().write("Finished " + req.getServletPath());
return;
}
switch (req.getServletPath()) {
case "/redirect":
resp.sendRedirect(new URL(req.getScheme() + "://" +
req.getServerName() + ":" + req.getServerPort() +
req.getRequestURI() + "?number=" + (number - 1)).toString());
return;
case "/forward":
final String forwardAddress = "/forward?number=" + (number - 1);
getServletContext().getRequestDispatcher(forwardAddress).forward(req,
resp);
}
}
}
It seems that under high load, 1000 threads in jmeter, Tomcat will
refuse some of the connections for nio2 connections but not for nio,
further it seems that these failures happen considerably earlier than
the configuration page would suggest would be the case. The
configuration suggests that if acceptCount is high enough for the
number of connections then they will be queued prior to reaching the
processing threads, so a small number of processing threads can exist
with a queue of connection feeding them, it seems like until
connectionTimeout is reached connections shouldn't be refused, but
that is not what occurs. In fact acceptCount seems to have very little
effect.
Are you testing on localhost, or over a real network connection? If a
real network, what kind of network? How many JMeter instances vs Tomcat
instances?
In short, my questions are:
Why is the nio2 connector type worse at this than nio type?
Let's table that for now.
Why are connections refused before acceptCount is reached, or
connectionTimeout is reached?
How are you measuring the size of the OS's TCP connection queue? What
makes you think that the OS has allocated exactly acceptCount entries in
the TCP connection queue? What makes you think acceptCount has been
reached? Or not yet reached?
What do you think connectionTimeout does, and when do you think it applies?
I'm guessing that each forward or redirect effectively counts as an
extra connection, as removing the redirects and multipling the number
of jmeter threads suggests that is the case, am I correct here?
A redirect will cause one connection to be terminated (at least
logically) and a new connection established. Assuming you are using
KeepAlives from JMeter, the same underlying TCP connection will likely
be used for the first and second requests. acceptCount probably doesn't
apply, since the connection has definitely been established.
For a "forward", the connection is definitely maintained. The client is
unaware of the fact that it is being sent back through the
request-processing pipeline as if there were a new request being made.
At this point, acceptCount, connectionTimeout, and everything else
you've been talking about is no longer an issue because the connection
has been accepted and request-processing has begun.
Also, I feel like it would help if there were better documentation
around the differences between nio2 and nio, as, for example, the
connector comparison part makes them sound almost the same.
The differences are mostly in the uses of the underlying Java APIs. If
you are familiar with the differences between NIO and NIO2 in Java, then
the differences between the connectors will be self-evident. If you are
unfamiliar with those differences, listing them won't help very much.
NIO is significantly different from BIO (blocking I/O) and therefore
requires a very different I/O model than BIO. NIO and NIO2 are much more
similar to each other. When NIO2 was introduced, it looked as though NIO
had been a stepping-stone between BIO and NIO2 and that NIO2 would
definitely be the way to go into the future, as the APIs were cleaner
and generally offered the best performance. The Java VM has been
undergoing a re-implementation of NIO to bring some of those performance
improvements "back" to NIO from NIO2 and so the difference is becoming
less important at this point. It pretty much comes down to API usage at
this point.
Hope that helps,
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org