Monday, September 23, 2013

Don't forget to use NIO if you are doing Async stuff with servlet 3.0 and using Tomcat 7 or below

If you are using Servlet 3.0 API to do some async stuff, do not forget to switch to NIO Connector by setting protocol attribute of the connector element in server.xml and using an executor. There are two important reasons for this: Thread pooling and timeout behavior of AsyncListener.

About Threads

There are 10 threads in my ExecutorService to handle requests in my AsyncContext pool. Here is a sample; let's assume that we push awesome data to clients in a comet fashion such:

If you leave Tomcat 7's default configuration; you will have n+10 threads. "n" is the number of requests. This is due to nature of blocking connectors. This might be useful for some applications (where for example thread local variables are highly used etc.). However; due to nature of the asynchronous job we are doing (we are pushing data to client when an event occurs) what we like to achieve is to satisfy all the clients with less threads; since most of the time threads are doing nothing but waiting.

Change your connector to NIO and use a thread pool for the NIO connector as seen from a server.xml fragment below:/p>

Connect with jprofiler; send 500 threads with jmeter; you will see only ten threads at the front; delivering those requests to 10 worker threads we defined above. To make it really look like a node.js; set maxThreads="1" minSpareThreads="1" of executor element. There were no changes in performance in my case due to fact that I wait for a second in my loop which schedules pushes to clients; so each client is pushed once a second approximately. In real life; an event will cause this push.

I really like this architecture rather then node.js due to fact that I know exactly the thread counts and I can manage them all. And please post me why node.js is better? I just can not understand. You have more libraries in java, you can integrate with many other systems easily; you can write in java,ruby,js,groovy,scala etc..

About Timeout

If your are setting timeout on AsyncContext such:

And then add an AsyncListener to that AsyncContext; OnTimeout of AsyncListener is called depending on which connector of Tomcat you are using.

If you are using Http11Protocol (BIO): callback is called exactly the time passed from the first request. If you give a high timeout and user closes his browser; still timeout is not called and you have to push data since you are not aware of it.

If you are using org.apache.coyote.http11.Http11NioProtocol (NIO); callback is called exactly the time you set after the connection is closed (for example if the browser is closed).

5 comments: