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

Reply via email to