I have an application that links users so they can chat.  My client
operates within a browser.  To be firewall friendly and avoid client
server sockets listening for incoming requests, I implemented the client
so that it makes http requests and sits and waits (maybe for minutes on
end) until it gets a response.  And each client has 2 threads that are
constantly waiting for an http response from 2 different urls (which
ties up 2 servlet threads).  I knew full well that this would be thread
heavy on the tomcat server side but thought I'd try it out.  The server
is tomcat 5.5.20 running on Windows XP Pro with 1GB of RAM.  After some
preliminary load testing, I find I'm able to handle about 500 simulated
users (each sending a message every 30 seconds) concurrently
communicating before getting connection refused messages.  I would like
to improve that.

So with each client having 2 threads constantly waiting on servlet
requests, that's 2 servlet threads per client or 1000 threads on the
server, which seems like a lot to me.  With 500 clients communicating
every 30 seconds, fairly evenly distributed, that's about 16 requests
per second.  It seems like I should be able to do better than that.

Initially when running my load test, I ran into OutOfMemoryErrors:
unable to create new native thread.  Lowering the thread stack size in
Tomcat's configuration dialog seemed to help.  Now the limiting issue is
that my clients receive "connection timed out" and "read timed out"
messages. 

On the client I see the following stacks:
java.net.ConnectException: Connection timed out: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(Unknown Source)
    at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at sun.net.NetworkClient.doConnect(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient.<init>(Unknown Source)
    at sun.net.www.http.HttpClient.New(Unknown Source)
    at sun.net.www.http.HttpClient.New(Unknown Source)
    at
sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown
Source)
    at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
    at com.seekspeak.applet.URLTalker.initConnection(URLTalker.java:44)
    at com.seekspeak.applet.URLTalker.send(URLTalker.java:50)
    at
com.seekspeak.test.load.RecipientTest$RefreshThread.run(RecipientTest.java:206)

java.net.SocketTimeoutException: Read timed out
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(Unknown Source)
        at java.io.BufferedInputStream.fill(Unknown Source)
        at java.io.BufferedInputStream.read1(Unknown Source)
        at java.io.BufferedInputStream.read(Unknown Source)
        at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
        at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
        at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown So
urce)
        at java.net.HttpURLConnection.getResponseCode(Unknown Source)
        at com.seekspeak.applet.URLTalker.send(URLTalker.java:54)
        at
com.seekspeak.test.load.Communicator$ListenThread.run(Communicator.ja
va:217)

In the catalina log, the only problem I see is this stack:

Oct 1, 2006 7:59:01 PM org.apache.catalina.core.StandardWrapperValve invoke
WARNING: Servlet.service() for servlet invoker threw exception
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at
org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:747)
    at
org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:777)
    at
org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:115)
    at
org.apache.coyote.http11.InternalInputBuffer.doRead(InternalInputBuffer.java:712)
    at org.apache.coyote.Request.doRead(Request.java:418)
...

CPU-wise the server never breaks a sweat, rarely rising above 5% cpu. 
My load test client is running on a separate machine from the server. 

My question is: how can I best improve the performance?  Is the server
really refusing client connections or is the load test bogging down and
reporting spurious messages (the load test uses many threads as well)? 
Is the high # of threads on the server a problem?  Would running on
Linux or another OS help?  Is there a way for me to minimize the # of
servlet threads required?

Since my servlet threads don't really do anything but sit around
blocking until being notified to complete the client's request, it seems
like I could just have a small number of threads and keep a map of open
http connections.  When necessary I could just have one of these threads
find the appropriate client connection, send output, and then close the
connection.  Since Tomcat operates on a single thread per servlet
request model, my issue is that doing the above will require substantial
changes to tomcat's Http11Protocol and like PoolTcpEndpoint classes. 
I'd really prefer to avoid monkeying with the tomcat code if possible.

And yes, peer to peer would be much less resource intensive, but I'm
trying to make an easy to install and run web app.  I don't want clients
trying to open server sockets on ports that might be blocked by firewalls.

Thanks for any thoughts,
Peter

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to