tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From André Warnier ...@ice-sa.com>
Subject Re: Tomcat Behavior on Multiple HTTP requests from same browser
Date Wed, 20 Mar 2013 18:25:41 GMT
Saurabh Agrawal wrote:
> -----Original Message-----
> From: André Warnier [mailto:aw@ice-sa.com] 
> Sent: Wednesday, March 20, 2013 3:27 PM
> To: Tomcat Users List
> Subject: Re: Tomcat Behavior on Multiple HTTP requests from same browser
> 
> Christopher Schultz wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA256
>>
>> Saurabh,
>>
>> On 3/19/13 9:46 PM, Saurabh Agrawal wrote:
>>> <Executor     name="hybrisExecutor" namePrefix="hybrisHTTP" 
>>> maxThreads="${tomcat.maxthreads}" 
>>> minSpareThreads="${tomcat.minsparethreads}" 
>>> maxIdleTime="${tomcat.maxidletime}"/>  

<Connector
>>> port="${tomcat.ajp.port}" maxHttpHeaderSize="8192" maxThreads="200"
>>>  protocol="org.apache.coyote.ajp.AjpProtocol" 
>>> executor="hybrisExecutor" enableLookups="false" acceptCount="100" 
>>> connectionTimeout="20000" URIEncoding="UTF-8" 
>>> disableUploadTimeout="true" />
>>>
>>> <Connector port="${tomcat.http.port}" maxHttpHeaderSize="8192" 
>>> maxThreads="${tomcat.maxthreads}" 
>>> protocol="org.apache.coyote.http11.Http11Protocol" 
>>> executor="hybrisExecutor" enableLookups="false" acceptCount="100" 
>>> connectionTimeout="20000" URIEncoding="UTF-8" 
>>> disableUploadTimeout="true" />

>> Note that your <Executor> has maxThreads="200" and your <Connector>
>> uses that <Executor>: your ${tomcat.maxthreads} is being ignored.
>>
> That, and the default keepalive setting, are probably the keys here.
> And the observation of Chuck about the HTTP and AJP connectors. Over which Connector
do 
> the test requests actually come in ?
> 
> Saurabh - The actual front end requests come on AJP port. We are using AJP protocol for
communication between Apache and Tomcat.

Right. So then I suppose that Christopher's note is not applicable.  Probablya he misread,

because the way in which you pasted the configuration in the email makes it difficult to 
read, after a couple of cut-and-paste.
As far as I can tell, the AJP connector refers to the Executor, and the Executor specifies

maxThreads="${tomcat.maxthreads}".

The main point of Christopher was that you specify a "maxThreads" parameter in both of 
your Connectors, but because they both use the Executor, this parameter is being ignored 
in the <Connector>, and it is only the maxThreads in the Executor that counts.

  It helps in load balancing across the application servers in cluster. There is a 
separate internal application (not exposed on internet) used by CMS team which is using 
HTTP connector. I hope that clarifies.
>
Yes.

> And a question : is the "simulation" with the 10000 clients really comparable to what
you 
> expect in the reality ?  For example, if the simulation requests one page per client,
and 
> then does nothing else with that page; but the real clients would get a page, and then

> immediately request the 50 thumbnail images referenced by that page, conditions would
be 
> really different, and keepalive would have a very different effect.
> 
> Saurabh - The way we have configured our user journeys are as follows:
> 
> User 1: Hits homepage, clicks football link on home page, makes a selection, adds to
cart and checkout. So this is one user journey which triggers multiple requests. 

Hi. Your usage of "user journey" is a bit obscure (to me at least) in the context of 
analysing a matter of tomcat request/response performance.
I kind of understand what you mean, but it does not really provide the answer to the 
questions :
- is this what you are using in your tests ?
- are you doing this same series of requests for each of your 10000 "test clients" ?
- does this represent (more or less) what you are expecting later "in production" ?

The point here was to avoid a case where you would be "optimising" the parameters in 
function of a benchmark test, and then find out later that your production case is totally

different, and your optimal benchmark settings are totally inappropriate for the 
production case.

 > All our assets are served from L3 CDN. So the asset requests never come to the 
application server.

That, I do not understand. I do not understand what you mean by "assets" here, and I do 
not understand "L3 CDN". So I cannot tell of this is relevant or not to the problem.
Have pity for the people trying to help you here, who only know Tomcat and HTTP/AJP.
Try to use vocabulary that we understand, and you may get better help.

 > We have not  set keep alive explicitly anywhere in tomcat.
 >
What Chuck was telling you in an earlier message, is that even if you do not set it 
explicitly, it is set to some default non-zero value by Tomcat.
Look at this page in the on-line documentation :
http://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html#Standard_Implementations

So, by default (unless you explicitly define it),

keepAliveTimeout :	

The number of milliseconds this Connector will wait for another AJP request before closing

the connection. The default value is to use the value that has been set for the 
connectionTimeout attribute.

and

connectionTimeout	

The number of milliseconds this Connector will wait, after accepting a connection, for the

request URI line to be presented. The default value for AJP protocol connectors is -1 
(i.e. infinite).

So, by default, the keepAliveTimeout is set to "infinite".

So now, read very carefully, because this describes a very specific set of circumstances,

which are not really applicable to you, but it is just for basic understanding.

/If/ your clients were connecting directly to a Tomcat basic HTTP Connector (named BIO), 
and you did not set any explicit keepAliveTimeout or connectionTimeout
and /If/ you were not using an Executor
/Then/ what would happen is this :
1) the client opens a connection to the server's HTTP connector, requesting a "keepalive"

connection (that is what browsers do by default in HTTP 1.1)
2) the server, by default, considers this connection as "persistent"
3) the server (in this case, the Connector) allocates a Thread to this connection, and 
this Thread now listens to what the client is going to say
4) the client sends one request on this connection
5) the allocated Thread receives the request, processes the request, and sends the 
response. Then it waits, to see if another request comes on the same connection.
And if the client keeps the connection open, but does not send any additional request on 
that connection, the Thread will wait theoretically forever (because that is what the 
documentation says about the default value of these parameters).
So /in this particular case/, you would have one Tomcat Thread that is now dedicated to 
this connection, doing nothing, but being unavailable to process any other request from 
any other client.

In other words, /in the particular set of conditions above/, if you wanted to avoid this 
situation, then you should set the keepAliveTimeout *explicitly*, to some reasonable value.

What is a reasonable value ?
That depends very much on your application.

Let's imagine a counter-example, and suppose that the connection was not a keepalive 
connection.
In that case, for each new request of the client, the client would have to create a *new*

TCP connection to the server, to send one request and receive one response. Then the 
server would close the connection, and for the next request the client would again need to

open a new connection.
That would be fine if a client was only sending a single request from time to time, 
because then you would not be tying up resources on the server, that can be better used 
for something else.
But it would be inefficient if the client always retrieves a first html page, and then in

that page there are 10 embedded images that the client also needs to retrieve. The client

would then have to open and close 10 consecutive times a new connection, each time to 
retrieve one single image.
So if you know that your application is so that a client will always need to retrieve 
several "objects" one after the other in a short interval, it is better to use one single

connection to do this, and thus to ask for a "persistent" or "keep-alive" connection.

You should set the keepAliveTimeout to a time sufficient so that the client has the time 
to request all the additional objects that it wants, before the server closes the connection.
But it should not be too long, because otherwise the Thread is going to wait a long time 
after the client has sent his last request, before the Thread decides that it has waited 
long enough, closes the connection, and returns to the pool of available Threads, to do 
something else.
So in the practice today, with normal Internet connection speeds, and normal clients and 
servers, a keepAliveTimeout of maximum 5 seconds is probably more than enough.
And for that, you should set it /explicitly/ to 5000 (milliseconds).

Now your case is a bit different, because
- you are not using the HTTP BIO connector (you use AJP)
- in front of your Tomcat, is an Apache httpd server.  This server has its own keep-alive

settings which apply to the connection of the client with Apache httpd.  And these 
keep-alive settings are a bit different from the Tomcat ones (for example, there is a 
keep-alive timeout, but also a MaxKeepAliveRequests)
- between Apache httpd and Tomcat, there is the mod_jk module in Apache, and that module 
uses its own timeouts (as set in workers.properties), and in addition it uses itself a 
pool of connections to Tomcat, and this pool of connections has its own rules for keeping

alive a connection between Apache and Tomcat.

But the basic principles above apply, and may explain why you are seeing what appears to 
be one Thread dedicated to one client, forever.











---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message