Re: bindOnInit and maxConnections for AJP connectors

2011-05-03 Thread Mark Thomas
On 21/04/2011 20:21, Mark Thomas wrote:
 On 06/04/2011 22:51, Tim Whittington wrote:
 On Wed, Apr 6, 2011 at 11:16 PM, Mark Thomas ma...@apache.org wrote:
 On 05/04/2011 10:50, Tim Whittington wrote:
 Is what's actually going on more like:

 APR: use maxConnections == pollerSize (smallest will limit, but if
 pollerSize  maxConnections then the socket backlog effectively won't
 be used as the poller will keep killing connections as they come in)

 NIO: use maxConnections to limit 'poller size'

 HTTP: use maxConnections. For keep alive situations, reduce
 maxConnections to something closer to maxThreads (the default config
 is 10,000 keepalive connections serviced by 200 threads with a 60
 second keepalive timeout, which could lead to some large backlogs of
 connected sockets that take 50 minutes to get serviced)
 
 This is still an issue. I'm still thinking about how to address it. My
 current thinking is:
 - BIO: Introduce simulated polling using a short timeout (see below)
 - NIO: Leave as is
 - APR: Make maxConnections and pollerSize synonyms
 - All: Make the default for maxConnections 8192 so it is consistent with
 the current APR default.
 
 The other option is dropping maxConnections entirely from the NIO and
 APR connectors. That would align the code with the docs. The only
 downside is that the NIO connector would no longer have an option to
 limit the connections. I'm not sure that is much of an issue since I
 don't recall any demands for such a limit from the user community.

Apologies for what I expect will turn out to be a long e-mail.

I have reached the point where I believe the best way forward is:
- remove maxConnections from NIO and APR
- remove the ability to set maxConnections for BIO and hard code it to
maxThreads
- restore the disable keep-alive when 75% BIO threads are in use

My reasoning is as follows:
- Servlet 3.0 async requests mean that current connections in use may be
greater then current threads in use.

- This provides potential efficiency savings as less threads are required.

- That connections may be greater than threads led to the new
maxConnections attribute.

- maxConnections  maxThreads introduces an issue where a connection
with data may be in the connection queue waiting for a thread whilst all
the threads are busy doing nothing waiting for data on connections that
will eventually time out.

- This issue can be fixed with simulated polling.

- Testing showed that simulated polling was very CPU intensive (I saw a
typical increase from ~40% to ~50% CPU usage with 4 Tomcat threads, 2
'fast' client threads making requests as fast as they could, 10 'slow'
client threads making a request every 5s and a pollTime of 100ms on an
8-core machine.

- The additional resources required by simulated polling are likely to
be greater than those saved by reduced thread usage.

- It is therefore better to just increase maxThreads, expecting that not
all of them will be used and hard-code maxConnections to the same number
as maxThreads. Better still, just use NIO.

Further, the complexity of BIO code required to support:
- Optional configuration of maxConnections  maxThreads
- simulated polling when maxConnections  maxThreads
- auto-disabling of keep-alive for users that don't want the overhead of
simulated polling when maxConnections == maxThreads
was getting to the point where I had stability concerns.

Given the above, and assuming there are no objections, I intend to
implement the way forward I set out above tomorrow.

Cheers,

Mark



-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-05-03 Thread Filip Hanik - Dev Lists

On 5/3/2011 10:50 AM, Mark Thomas wrote:

On 21/04/2011 20:21, Mark Thomas wrote:

On 06/04/2011 22:51, Tim Whittington wrote:

On Wed, Apr 6, 2011 at 11:16 PM, Mark Thomasma...@apache.org  wrote:

On 05/04/2011 10:50, Tim Whittington wrote:

Is what's actually going on more like:

APR: use maxConnections == pollerSize (smallest will limit, but if
pollerSize  maxConnections then the socket backlog effectively won't
be used as the poller will keep killing connections as they come in)

NIO: use maxConnections to limit 'poller size'

HTTP: use maxConnections. For keep alive situations, reduce
maxConnections to something closer to maxThreads (the default config
is 10,000 keepalive connections serviced by 200 threads with a 60
second keepalive timeout, which could lead to some large backlogs of
connected sockets that take 50 minutes to get serviced)

This is still an issue. I'm still thinking about how to address it. My
current thinking is:
- BIO: Introduce simulated polling using a short timeout (see below)
- NIO: Leave as is
- APR: Make maxConnections and pollerSize synonyms
- All: Make the default for maxConnections 8192 so it is consistent with
the current APR default.

The other option is dropping maxConnections entirely from the NIO and
APR connectors. That would align the code with the docs. The only
downside is that the NIO connector would no longer have an option to
limit the connections. I'm not sure that is much of an issue since I
don't recall any demands for such a limit from the user community.

Apologies for what I expect will turn out to be a long e-mail.

I have reached the point where I believe the best way forward is:
- remove maxConnections from NIO and APR
- remove the ability to set maxConnections for BIO and hard code it to
maxThreads

-1
maxConnections serves a purpose. It protects against a DoS.
There must be a way to configure a system to eventually push back, and not just 
keep accepting connections.
Therefor the maxConnections should stay.

- restore the disable keep-alive when75% BIO threads are in use
why, make it configurable. I would believe that on many systems, the queued approach that BIO has, still can provide significant improvement 
in performance. If I don't want queued behavior, I'll just turn off keep alive.



My reasoning is as follows:
- Servlet 3.0 async requests mean that current connections in use may be
greater then current threads in use.

- This provides potential efficiency savings as less threads are required.

- That connections may be greater than threads led to the new
maxConnections attribute.

the maxConnections attribute is simply to restrict the acceptor thread from 
just going on and on.
It had nothing to do with servlet 3 or async. It's a protective measure for the 
server.


- maxConnections  maxThreads introduces an issue where a connection
with data may be in the connection queue waiting for a thread whilst all
the threads are busy doing nothing waiting for data on connections that
will eventually time out.

and this is still better than simply not accepting any connections at all.
Right now, in order to work around the blocking aspect, one has to configure 
acceptCount so that connections are not simply turned away.

- This issue can be fixed with simulated polling.

I wouldn't do simulated polling. I'm not sure what benefit there would be.

- Testing showed that simulated polling was very CPU intensive (I saw a
typical increase from ~40% to ~50% CPU usage with 4 Tomcat threads, 2
'fast' client threads making requests as fast as they could, 10 'slow'
client threads making a request every 5s and a pollTime of 100ms on an
8-core machine.

- The additional resources required by simulated polling are likely to
be greater than those saved by reduced thread usage.

- It is therefore better to just increase maxThreads, expecting that not
all of them will be used and hard-code maxConnections to the same number
as maxThreads. Better still, just use NIO.


you still need maxConnection



Further, the complexity of BIO code required to support:
- Optional configuration of maxConnections  maxThreads
- simulated polling when maxConnections  maxThreads
- auto-disabling of keep-alive for users that don't want the overhead of
simulated polling when maxConnections == maxThreads
was getting to the point where I had stability concerns.

Given the above, and assuming there are no objections, I intend to
implement the way forward I set out above tomorrow.


I'm confused about what you are trying to do or achieve. What problems are you 
trying to solve?
This email thread started with two missing attributes.
I'd start a new thread describing the problem you are having.

best
Filip


Cheers,

Mark



-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



-
No virus found in this message.
Checked by AVG - www.avg.com
Version: 

Re: bindOnInit and maxConnections for AJP connectors

2011-05-03 Thread Mark Thomas
On 03/05/2011 18:07, Filip Hanik - Dev Lists wrote:
 I'm confused about what you are trying to do or achieve. What problems
 are you trying to solve?
 This email thread started with two missing attributes.
 I'd start a new thread describing the problem you are having.

OK. I'll pull out the BIO performance issues into a new thread.

Mark



-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-21 Thread Mark Thomas
On 05/04/2011 09:51, Tim Whittington wrote:
 In the AJP standard implementation docs, the following are not
 mentioned, although they're properties of AbstractEndpoint and
 probably should work:
 - bindOnInit
 - maxConnections
 Am I right in assuming these should be possible in the AJP connector
 (my reading of the code indicates they are - just wanted to check if
 something arcane was going on)?

If fixed the docs for bindOnInit

maxConnections is still TBD.

Mark

 If so I'll update the docs.
 
 cheers
 tim
 
 -
 To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
 For additional commands, e-mail: dev-h...@tomcat.apache.org
 




-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-21 Thread Mark Thomas
On 06/04/2011 22:51, Tim Whittington wrote:
 On Wed, Apr 6, 2011 at 11:16 PM, Mark Thomas ma...@apache.org wrote:
 On 05/04/2011 10:50, Tim Whittington wrote:
 Is what's actually going on more like:

 APR: use maxConnections == pollerSize (smallest will limit, but if
 pollerSize  maxConnections then the socket backlog effectively won't
 be used as the poller will keep killing connections as they come in)

 NIO: use maxConnections to limit 'poller size'

 HTTP: use maxConnections. For keep alive situations, reduce
 maxConnections to something closer to maxThreads (the default config
 is 10,000 keepalive connections serviced by 200 threads with a 60
 second keepalive timeout, which could lead to some large backlogs of
 connected sockets that take 50 minutes to get serviced)

This is still an issue. I'm still thinking about how to address it. My
current thinking is:
- BIO: Introduce simulated polling using a short timeout (see below)
- NIO: Leave as is
- APR: Make maxConnections and pollerSize synonyms
- All: Make the default for maxConnections 8192 so it is consistent with
the current APR default.

The other option is dropping maxConnections entirely from the NIO and
APR connectors. That would align the code with the docs. The only
downside is that the NIO connector would no longer have an option to
limit the connections. I'm not sure that is much of an issue since I
don't recall any demands for such a limit from the user community.

 There are a number of issues with the current BIO implementation.

 1. Keep-alive timeouts
Fixed.

 2. The switch to a queue does result in the possibility of requests with
 data being delayed by requests without data in keep-alive.
Still TODO.

 3. HTTP pipe-lining is broken (this is bug 50957 [1]).
Fixed.

 The fix for issue 2 is tricky. The fundamental issue is that to resolve
 it and to keep maxConnections  maxThreads we need NIO like behaviour
 from a BIO socket which just isn't possible.
 Fixing 1 will reduce the maximum length of delay that any one request
 might experience which will help but that won't address the fundamental
 issue.
 For sockets in keepalive, I considered trying to fake NIO behaviour by
 using a read with a timeout of 1ms, catching the SocketTimeoutException
 and returning them to the back of the queue if there is no data. The
 overhead of that looks to be around 2-3ms for a 1ms timeout. I'm worried
 about CPU usage but for a single thread this doesn't seem to be
 noticeable. More testing with multiple threads is required. The timeout
 could be tuned by looking at the current number of active threads, size
 of the queue etc. but it is an ugly hack.
 Returning to the pre [3] approach of disabling keep-alive once
 connections  75% of threads would fix this at the price of no longer
 being able to support maxConnections  maxThreads.
 
 
 Yeah, I went down this track as well before getting to the Just use
 APR/NIO state of mind.
 It is an ugly hack, but might be workable if the timeout is large
 enough to stop it being a busy loop on the CPU.
 With 200 threads, even a 100ms timeout would give you a 'reasonable' 
 throughput.
 Even if we do this, I still think maxConnections should be somewhat
 closer to maxThreads than it is now if the BIO connector is being
 used.

We can make the timeout configurable but 100ms shouldn't be too bad. I
have a simple, scaled-down test case and this approach looks good in
terms of throughput but there are a few kinks I need to iron out. Also
the CPU usage looked rather high, although that might be a side-effect
of one of the kinks. If the issues can't be ironed out then we'll need a
major rethink about this - probably heading back towards a TC6 style
solution.

Mark



-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-08 Thread Tim Whittington
On Fri, Apr 8, 2011 at 2:40 AM, Christopher Schultz
ch...@christopherschultz.net wrote:
 Mark,

 I understand that a fix has already been applied, but...

 On 4/6/2011 7:16 AM, Mark Thomas wrote:
 I thought of two options for issue 3:
 a) Assign a processor (+ inputbuffer, output buffer etc.) to a socket
 and don't recycle it until the socket is closed.
 - Increases memory requirements.
 - Fixes issue 3
 - Retains current request processing order.

 b) Check the input buffer at the end of the loop in
 Http11Processor#process() and process the next request if there is any
 data in the input buffer.
 - No Increase in memory requirements.
 - Fixes issue 3
 - Pipelined requests will get processed earlier (before they would have
 been placed at the back of the request processing queue)

 I think option b) is the way to go to fix issue

 What about a third option that is essentially (a) except that you trim
 the input buffer and discard the already-processed request(s) from it.
 The input buffer stays bound to the request and continues where it
 left-off when another request processor becomes available.

 That would maintain scheduling fairness and hopefully not require much
 in the way of memory usage. Since pipelining requests with entities is
 not a good idea, the chances of getting a large amount of data in the
 input buffer is relatively low. There's also a limit on the size of that
 buffer, too.

 Would that still represent too large of a memory requirement?

The input buffer is 8k by default (max header size), so this could be
significant with a large maxConnections.
Pruning the buffers to retain only required space would generate a lot
of garbage, so probably not a good option either.
If the fairness becomes a practical problem, reducing
maxKeepAliveRequests (100 by default) would force pipelining clients
to the back of the queue regularly.

We could go with option a) and use the processor cache size to bound
the 'memory vs fairness tradeoff' - e.g. place pipeline connections
back on the queue, but add their processor to a 'borrowed' queue
without recycling. If the total processor limit is met and the
recycled processor cache is exhausted, then a borrowed processor is
recalled, the pipelined connection drained, and the processor then
made available for use.
The default processorCache is 200 (matches maxThreads), so default
behaviour would be unfair.

-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-08 Thread Filip Hanik - Dev Lists

On 4/8/2011 2:50 AM, Tim Whittington wrote:

The input buffer is 8k by default (max header size), so this could be
significant with a large maxConnections.

significant in 1990 maybe :) even with 20k connections, this be a drop in the 
ocean compared to memory usage for today's applications



-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-08 Thread Christopher Schultz
Tim,

On 4/8/2011 4:50 AM, Tim Whittington wrote:
 On Fri, Apr 8, 2011 at 2:40 AM, Christopher Schultz
 ch...@christopherschultz.net wrote:
 Mark,

 I understand that a fix has already been applied, but...

 On 4/6/2011 7:16 AM, Mark Thomas wrote:
 I thought of two options for issue 3:
 a) Assign a processor (+ inputbuffer, output buffer etc.) to a socket
 and don't recycle it until the socket is closed.
 - Increases memory requirements.
 - Fixes issue 3
 - Retains current request processing order.

 b) Check the input buffer at the end of the loop in
 Http11Processor#process() and process the next request if there is any
 data in the input buffer.
 - No Increase in memory requirements.
 - Fixes issue 3
 - Pipelined requests will get processed earlier (before they would have
 been placed at the back of the request processing queue)

 I think option b) is the way to go to fix issue

 What about a third option that is essentially (a) except that you trim
 the input buffer and discard the already-processed request(s) from it.
 The input buffer stays bound to the request and continues where it
 left-off when another request processor becomes available.

 That would maintain scheduling fairness and hopefully not require much
 in the way of memory usage. Since pipelining requests with entities is
 not a good idea, the chances of getting a large amount of data in the
 input buffer is relatively low. There's also a limit on the size of that
 buffer, too.

 Would that still represent too large of a memory requirement?
 
 The input buffer is 8k by default (max header size), so this could be
 significant with a large maxConnections.
 Pruning the buffers to retain only required space would generate a lot
 of garbage, so probably not a good option either.

Are those buffers ever discarded? I guess it comes down to whether the
8k buffer belongs to the connection or to the request. It looks like
the bug arises from the buffer being treated like it belongs to the
request when it really belongs to the connection.

I agree, switching to a request-owned buffer strategy would certainly
increase the memory footprint since you'd need a buffer for each pending
request (which may be quite high when using NIO an/or async). Thanks for
clarifying that.

 If the fairness becomes a practical problem, reducing
 maxKeepAliveRequests (100 by default) would force pipelining clients
 to the back of the queue regularly.

How would this work, though? If the bug under discussion arises from a
connection essentially disconnecting one of these buffers from the
request whence it came, doesn't re-queuing the request re-introduce the bug?

-chris



signature.asc
Description: OpenPGP digital signature


Re: bindOnInit and maxConnections for AJP connectors

2011-04-08 Thread Filip Hanik - Dev Lists

On 4/6/2011 3:51 PM, Tim Whittington wrote:

  b) Check the input buffer at the end of the loop in
  Http11Processor#process() and process the next request if there is any
  data in the input buffer.
  - No Increase in memory requirements.
  - Fixes issue 3
  - Pipelined requests will get processed earlier (before they would have
  been placed at the back of the request processing queue)

  I think option b) is the way to go to fix issue

+1
It's an unfair scheduling, but given issue 2 that's a fairly moot
point with the BIO connector.

sounds reasonable. this is how we used to do it (we may still) in APR.
it avoids one context switch not needed, and in NIO we could do this too, since 
we can even check the network buffer without blocking

best
Filip





-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-08 Thread Tim Whittington
 Are those buffers ever discarded? I guess it comes down to whether the
 8k buffer belongs to the connection or to the request. It looks like
 the bug arises from the buffer being treated like it belongs to the
 request when it really belongs to the connection.

 I agree, switching to a request-owned buffer strategy would certainly
 increase the memory footprint since you'd need a buffer for each pending
 request (which may be quite high when using NIO an/or async). Thanks for
 clarifying that.

 If the fairness becomes a practical problem, reducing
 maxKeepAliveRequests (100 by default) would force pipelining clients
 to the back of the queue regularly.

 How would this work, though? If the bug under discussion arises from a
 connection essentially disconnecting one of these buffers from the
 request whence it came, doesn't re-queuing the request re-introduce the bug?


I was thinking of closing the connection (as maxKeepAliveRequests) does now.
The re-connect would go to the back of the queue.

-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-07 Thread Christopher Schultz
Mark,

I understand that a fix has already been applied, but...

On 4/6/2011 7:16 AM, Mark Thomas wrote:
 I thought of two options for issue 3:
 a) Assign a processor (+ inputbuffer, output buffer etc.) to a socket
 and don't recycle it until the socket is closed.
 - Increases memory requirements.
 - Fixes issue 3
 - Retains current request processing order.
 
 b) Check the input buffer at the end of the loop in
 Http11Processor#process() and process the next request if there is any
 data in the input buffer.
 - No Increase in memory requirements.
 - Fixes issue 3
 - Pipelined requests will get processed earlier (before they would have
 been placed at the back of the request processing queue)
 
 I think option b) is the way to go to fix issue

What about a third option that is essentially (a) except that you trim
the input buffer and discard the already-processed request(s) from it.
The input buffer stays bound to the request and continues where it
left-off when another request processor becomes available.

That would maintain scheduling fairness and hopefully not require much
in the way of memory usage. Since pipelining requests with entities is
not a good idea, the chances of getting a large amount of data in the
input buffer is relatively low. There's also a limit on the size of that
buffer, too.

Would that still represent too large of a memory requirement?

-chris



signature.asc
Description: OpenPGP digital signature


Re: bindOnInit and maxConnections for AJP connectors

2011-04-06 Thread Mark Thomas
On 05/04/2011 10:50, Tim Whittington wrote:
 Is what's actually going on more like:
 
 APR: use maxConnections == pollerSize (smallest will limit, but if
 pollerSize  maxConnections then the socket backlog effectively won't
 be used as the poller will keep killing connections as they come in)
 
 NIO: use maxConnections to limit 'poller size'
 
 HTTP: use maxConnections. For keep alive situations, reduce
 maxConnections to something closer to maxThreads (the default config
 is 10,000 keepalive connections serviced by 200 threads with a 60
 second keepalive timeout, which could lead to some large backlogs of
 connected sockets that take 50 minutes to get serviced)

This is indeed the case. There are a number of issues with the current
BIO implementation.

1. Keep-alive timeouts
As per the TODO comment in Http11Processor#process(), the keep-alive
timeout needs to take account of the time spent in the queue.

2. The switch to a queue does result in the possibility of requests with
data being delayed by requests without data in keep-alive.

3. HTTP pipe-lining is broken (this is bug 50957 [1]). The sequence is:
- client sends 1 complete request and part of second request
- tomcat processes first request
- tomcat recycles the input buffer
- client sends remainder of second request
- tomcat sees an incomplete request and returns a 505
There are variations of this depending on exactly how much of the second
request has been read by Tomcat at the point the input buffer is
recycled. Note that r1086349 [2] has protected against the worst of what
could go wrong (mixed responses etc) but has not fixed the underlying issue.

The change that triggered all of the above issues is r822234 [3].

Reverting r822234 isn't an option as the async code depends on elements
of if.


The fix for issue 1 is simple so I do not intend to discuss it further.


The fix for issue 2 is tricky. The fundamental issue is that to resolve
it and to keep maxConnections  maxThreads we need NIO like behaviour
from a BIO socket which just isn't possible.
Fixing 1 will reduce the maximum length of delay that any one request
might experience which will help but that won't address the fundamental
issue.
For sockets in keepalive, I considered trying to fake NIO behaviour by
using a read with a timeout of 1ms, catching the SocketTimeoutException
and returning them to the back of the queue if there is no data. The
overhead of that looks to be around 2-3ms for a 1ms timeout. I'm worried
about CPU usage but for a single thread this doesn't seem to be
noticeable. More testing with multiple threads is required. The timeout
could be tuned by looking at the current number of active threads, size
of the queue etc. but it is an ugly hack.
Returning to the pre [3] approach of disabling keep-alive once
connections  75% of threads would fix this at the price of no longer
being able to support maxConnections  maxThreads.


I thought of two options for issue 3:
a) Assign a processor (+ inputbuffer, output buffer etc.) to a socket
and don't recycle it until the socket is closed.
- Increases memory requirements.
- Fixes issue 3
- Retains current request processing order.

b) Check the input buffer at the end of the loop in
Http11Processor#process() and process the next request if there is any
data in the input buffer.
- No Increase in memory requirements.
- Fixes issue 3
- Pipelined requests will get processed earlier (before they would have
been placed at the back of the request processing queue)

I think option b) is the way to go to fix issue


The fixes for 1  3 seem fairly straight forward and unless anyone
objects, I'll go ahead (when I get a little time) and implement those. I
think the fix for 2 needs some further discussion. What do folks think?


Mark



[1] https://issues.apache.org/bugzilla/show_bug.cgi?id=50957
[2] http://svn.apache.org/viewvc?rev=1086349view=rev
[3] http://svn.apache.org/viewvc?view=revrev=823234

 
 cheers
 tim
 
 On Tue, Apr 5, 2011 at 8:51 PM, Tim Whittington t...@apache.org wrote:
 In the AJP standard implementation docs, the following are not
 mentioned, although they're properties of AbstractEndpoint and
 probably should work:
 - bindOnInit
 - maxConnections
 Am I right in assuming these should be possible in the AJP connector
 (my reading of the code indicates they are - just wanted to check if
 something arcane was going on)?

 If so I'll update the docs.

 cheers
 tim

 
 -
 To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
 For additional commands, e-mail: dev-h...@tomcat.apache.org
 


-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-06 Thread Tim Whittington
On Wed, Apr 6, 2011 at 11:16 PM, Mark Thomas ma...@apache.org wrote:
 On 05/04/2011 10:50, Tim Whittington wrote:
 Is what's actually going on more like:

 APR: use maxConnections == pollerSize (smallest will limit, but if
 pollerSize  maxConnections then the socket backlog effectively won't
 be used as the poller will keep killing connections as they come in)

 NIO: use maxConnections to limit 'poller size'

 HTTP: use maxConnections. For keep alive situations, reduce
 maxConnections to something closer to maxThreads (the default config
 is 10,000 keepalive connections serviced by 200 threads with a 60
 second keepalive timeout, which could lead to some large backlogs of
 connected sockets that take 50 minutes to get serviced)

 This is indeed the case. There are a number of issues with the current
 BIO implementation.

 1. Keep-alive timeouts
 As per the TODO comment in Http11Processor#process(), the keep-alive
 timeout needs to take account of the time spent in the queue.

 2. The switch to a queue does result in the possibility of requests with
 data being delayed by requests without data in keep-alive.

 3. HTTP pipe-lining is broken (this is bug 50957 [1]). The sequence is:
 - client sends 1 complete request and part of second request
 - tomcat processes first request
 - tomcat recycles the input buffer
 - client sends remainder of second request
 - tomcat sees an incomplete request and returns a 505
 There are variations of this depending on exactly how much of the second
 request has been read by Tomcat at the point the input buffer is
 recycled. Note that r1086349 [2] has protected against the worst of what
 could go wrong (mixed responses etc) but has not fixed the underlying issue.

 The change that triggered all of the above issues is r822234 [3].

 Reverting r822234 isn't an option as the async code depends on elements
 of if.


 The fix for issue 1 is simple so I do not intend to discuss it further.


 The fix for issue 2 is tricky. The fundamental issue is that to resolve
 it and to keep maxConnections  maxThreads we need NIO like behaviour
 from a BIO socket which just isn't possible.
 Fixing 1 will reduce the maximum length of delay that any one request
 might experience which will help but that won't address the fundamental
 issue.
 For sockets in keepalive, I considered trying to fake NIO behaviour by
 using a read with a timeout of 1ms, catching the SocketTimeoutException
 and returning them to the back of the queue if there is no data. The
 overhead of that looks to be around 2-3ms for a 1ms timeout. I'm worried
 about CPU usage but for a single thread this doesn't seem to be
 noticeable. More testing with multiple threads is required. The timeout
 could be tuned by looking at the current number of active threads, size
 of the queue etc. but it is an ugly hack.
 Returning to the pre [3] approach of disabling keep-alive once
 connections  75% of threads would fix this at the price of no longer
 being able to support maxConnections  maxThreads.


Yeah, I went down this track as well before getting to the Just use
APR/NIO state of mind.
It is an ugly hack, but might be workable if the timeout is large
enough to stop it being a busy loop on the CPU.
With 200 threads, even a 100ms timeout would give you a 'reasonable' throughput.
Even if we do this, I still think maxConnections should be somewhat
closer to maxThreads than it is now if the BIO connector is being
used.


 I thought of two options for issue 3:
 a) Assign a processor (+ inputbuffer, output buffer etc.) to a socket
 and don't recycle it until the socket is closed.
 - Increases memory requirements.
 - Fixes issue 3
 - Retains current request processing order.

 b) Check the input buffer at the end of the loop in
 Http11Processor#process() and process the next request if there is any
 data in the input buffer.
 - No Increase in memory requirements.
 - Fixes issue 3
 - Pipelined requests will get processed earlier (before they would have
 been placed at the back of the request processing queue)

 I think option b) is the way to go to fix issue


+1
It's an unfair scheduling, but given issue 2 that's a fairly moot
point with the BIO connector.




 The fixes for 1  3 seem fairly straight forward and unless anyone
 objects, I'll go ahead (when I get a little time) and implement those. I
 think the fix for 2 needs some further discussion. What do folks think?


 Mark



 [1] https://issues.apache.org/bugzilla/show_bug.cgi?id=50957
 [2] http://svn.apache.org/viewvc?rev=1086349view=rev
 [3] http://svn.apache.org/viewvc?view=revrev=823234


 cheers
 tim

 On Tue, Apr 5, 2011 at 8:51 PM, Tim Whittington t...@apache.org wrote:
 In the AJP standard implementation docs, the following are not
 mentioned, although they're properties of AbstractEndpoint and
 probably should work:
 - bindOnInit
 - maxConnections
 Am I right in assuming these should be possible in the AJP connector
 (my reading of the code indicates they are - just wanted to 

bindOnInit and maxConnections for AJP connectors

2011-04-05 Thread Tim Whittington
In the AJP standard implementation docs, the following are not
mentioned, although they're properties of AbstractEndpoint and
probably should work:
- bindOnInit
- maxConnections
Am I right in assuming these should be possible in the AJP connector
(my reading of the code indicates they are - just wanted to check if
something arcane was going on)?

If so I'll update the docs.

cheers
tim

-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-05 Thread Tim Whittington
Further to this, the docs for maxConnections currently state:

This setting is currently only applicable to the blocking Java
connectors (AJP/HTTP).

But both the NIO and APR connectors use this setting in their Acceptor
implementations, limiting the number of concurrent connections before
they're accepted and handed off to the pollers.

It's possibly the case for the APR connector that pollerSize should be
used in preference (keeping maxConnections  pollerSize), but the NIO
connector doesn't have a poller size config option (the connector
summary describes it as 'restricted by mem'.

The Connector Comparison table (and the discussion of
connection/thread behaviour) in the HTTP connector docs are thus
slightly misleading.

Is what's actually going on more like:

APR: use maxConnections == pollerSize (smallest will limit, but if
pollerSize  maxConnections then the socket backlog effectively won't
be used as the poller will keep killing connections as they come in)

NIO: use maxConnections to limit 'poller size'

HTTP: use maxConnections. For keep alive situations, reduce
maxConnections to something closer to maxThreads (the default config
is 10,000 keepalive connections serviced by 200 threads with a 60
second keepalive timeout, which could lead to some large backlogs of
connected sockets that take 50 minutes to get serviced)

cheers
tim

On Tue, Apr 5, 2011 at 8:51 PM, Tim Whittington t...@apache.org wrote:
 In the AJP standard implementation docs, the following are not
 mentioned, although they're properties of AbstractEndpoint and
 probably should work:
 - bindOnInit
 - maxConnections
 Am I right in assuming these should be possible in the AJP connector
 (my reading of the code indicates they are - just wanted to check if
 something arcane was going on)?

 If so I'll update the docs.

 cheers
 tim


-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-05 Thread Sylvain Laurent

On 5 avr. 2011, at 11:50, Tim Whittington wrote:
 
 HTTP: use maxConnections. For keep alive situations, reduce
 maxConnections to something closer to maxThreads (the default config
 is 10,000 keepalive connections serviced by 200 threads with a 60
 second keepalive timeout, which could lead to some large backlogs of
 connected sockets that take 50 minutes to get serviced)

I think it was tc6 behavior, but it changed with tc7 : threads are now returned 
to the pool between requests, even with keep-alive connections.

Sylvain
-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org



Re: bindOnInit and maxConnections for AJP connectors

2011-04-05 Thread Mark Thomas
On 05/04/2011 19:42, Sylvain Laurent wrote:
 
 On 5 avr. 2011, at 11:50, Tim Whittington wrote:

 HTTP: use maxConnections. For keep alive situations, reduce
 maxConnections to something closer to maxThreads (the default config
 is 10,000 keepalive connections serviced by 200 threads with a 60
 second keepalive timeout, which could lead to some large backlogs of
 connected sockets that take 50 minutes to get serviced)
 
 I think it was tc6 behavior

Nope. tc6 behaviour was one thread per connection, including during
keep-alive.

, but it changed with tc7 : threads are now returned to the pool between
requests, even with keep-alive connections.

tc7 behaviour does return the thread to the pool but it is certainly
possible for something along the lines Tim is describing to happen
although I don't think the delay could be as long as 50 minutes. I'd
need to double check the code for keep-alive time-outs to be sure.

Mark



-
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org