Hi there,

I'm studying Servlet 3's async API using tomcat. I see following strange 
behavior from tomcat in a very simple test app!

I have following JMeter test plan:
Number of threads (users): 700
Ramp-Up period (in seconds): 23
Loop count: 1

So JMeter generates 30.43 requests per second and 304.3 requests per 10 
seconds. I'm planning to full tomcat's BIO pool and accept buffer :)

I have an always async test servlet which on destroy, I print tomcat 
container max used threads count. It prints 187 for me which is lower 
than 200 (tomcat default pool size) so I should not get any "connection 
refuse" but I get!

I have simulated a blocking operation by a sleep for 10 seconds. When my 
servlet gets a request, it quickly starts an async and add further 
processing to my own thread pool (container thread comes back to pool 
quickly, right). My own thread pool size is 310 which is greater than 
304.3 (requests in 10 seconds) so never full.

I've tested several times. Tomcat successfully returns from all requests 
below 326th but fails 102 requests from 326th to 700th with "connection 
refuse" and afew with "connection reset".

Why?! My own thread pool does the jobs and Tomcat's pool is free (my 
servlet uses 187 threads of tomcat at max).

Thanks in advance!

JMETER RESULT of RESPONSE TIMES:
Max: 60 seconds (lower then tomcat and asyncContext timeout)
MIN: 10 seconds
AVG: 37 seconds
ERR: 15%

CONFIGURATIONS:

Server.xml
<Connector port="7780" protocol="org.apache.coyote.http11.Http11Protocol"
                connectionTimeout="120000"
                redirectPort="7743" />

Async.java

package com.sstr.example;

import javax.servlet.*;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

@WebServlet(
         name = "async",
         value = {"/async"},
         asyncSupported = true,
         initParams = {
                 @WebInitParam(name = "JobPoolSize", value = "310")
         }
)
public class Async extends HttpServlet {

     public final int REQUEST_TIMEOUT = 120000;
     private ExecutorService exe;

     @Override
     public void init() throws ServletException {
         int size = Integer.parseInt(getInitParameter("JobPoolSize"));
         exe = Executors.newFixedThreadPool(
                 size,
                 new ThreadFactory() {
                     @Override
                     public Thread newThread(Runnable r) {
                         return new Thread(r, "Async Processor");
                     }
                 }
         );
     }

     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse 
resp) throws ServletException, IOException {
         final AsyncContext context = req.startAsync();
         context.setTimeout(REQUEST_TIMEOUT);
         exe.execute(new ContextExecution(context, 
Thread.currentThread().getName()));
     }

     @Override
     public void destroy() {
         System.out.println("Container MAX used threads: " + threadCount);
         exe.shutdown();
     }

     int threadCount = 0;
     class ContextExecution implements Runnable {

         final AsyncContext context;
         final String containerThreadName;

         public ContextExecution(AsyncContext context, String 
containerThreadName) {
             this.context = context;
             this.containerThreadName = containerThreadName;
         }

         @Override
         public void run() {
             try {
                 int threadNumber = 
Integer.parseInt(containerThreadName.substring(
                         containerThreadName.lastIndexOf('-')+1));
                 if(threadNumber > threadCount) {
                     threadCount = threadNumber;
                 }

                 // Simulate Time Consuming Task
                 Thread.sleep(10000);

                 ServletResponse resp = context.getResponse();
                 if (resp != null) {
                     resp.getWriter().write("Ok");
                 }

                 context.complete();
             } catch (Exception e) {
                 // Handle ?
             }
         }
     }
}

OUTPUT:

Container MAX used threads: 187

Reply via email to