Bug 41270 - TCP_DEFER_ACCEPT timeout set way too low
Summary: TCP_DEFER_ACCEPT timeout set way too low
Status: RESOLVED FIXED
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: Core (show other bugs)
Version: 2.2.3
Hardware: Other Linux
: P2 normal (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-12-30 18:35 UTC by dean gaudet
Modified: 2015-01-07 12:57 UTC (History)
1 user (show)



Attachments
set TCP_DEFER_ACCEPT to 30 seconds (641 bytes, patch)
2006-12-30 18:36 UTC, dean gaudet
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description dean gaudet 2006-12-30 18:35:24 UTC
the TCP_DEFER_ACCEPT code for linux sets the timeout to 1 second.  this is
totally broken... ideally the value should be configurable via AcceptFilter or
otherwise, but at a minimum it should be something like 30 seconds.

it's only by sheer luck that the current code doesn't cause havoc -- because the
kernel itself isn't doing the right thing with the timeout and is waiting a lot
longer than specified.

-dean
Comment 1 dean gaudet 2006-12-30 18:36:10 UTC
Created attachment 19332 [details]
set TCP_DEFER_ACCEPT to 30 seconds
Comment 3 Ruediger Pluem 2006-12-31 04:53:32 UTC
(In reply to comment #0)
> the TCP_DEFER_ACCEPT code for linux sets the timeout to 1 second.  this is
> totally broken... ideally the value should be configurable via AcceptFilter or
> otherwise, but at a minimum it should be something like 30 seconds.

I agree that it makes sense to keep this value configurable. But what do you
think is actually "totally broken" with the 1 second setting (provided the
kernel would do the right thing)? Do you think too much clients, which have
a slow / bad connection to the httpd server will not get a connection because
it is dropped by the kernel before they can sent data?

Question to the BSD guys: Is it possible to set a timeout for the BSD accept
filters accf_data and accf_http how long they should wait for a request until
they drop the socket?
Comment 4 Ruediger Pluem 2006-12-31 04:59:30 UTC
http://lkml.org/lkml/2000/10/21/80 provides also an interesting discussion on
the Linux kernel behaviour.
Comment 5 dean gaudet 2006-12-31 05:12:27 UTC
if there's any amount of packet loss (or geosynchronous orbit satellites
involved), the 3-way handshake will never complete if the server gives up after
1 second... i'm sure if you dig through the RFCs you'll find standards
requirements backing this up.

-dean
Comment 6 dean gaudet 2007-01-30 01:07:23 UTC
sorry, but i can't stand this being left as NEEDINFO when it should be obvious
to anyone that a one second timeout for the 3rd packet in a 3-way handshake is
insane.
Comment 7 dean gaudet 2007-01-30 01:34:37 UTC
btw, i've been running with a 30s setting for TCP_DEFER_ACCEPT for 13 months now
on a 40+ req/s website without any problems.  i really don't see the harm in
changing apache to have a sane setting for this value.
Comment 8 Joe Orton 2007-01-30 02:22:55 UTC
Agreed, thanks for the patch and analysis; committed as
http://svn.apache.org/viewvc?view=rev&rev=501364

I've prodded some kernel guys, hopefully someone can clarify the semantics of
the option argument and follow up your netdev post.
Comment 9 David Weekly 2007-02-05 17:07:02 UTC
The Linux tcp(7) man page indicates that the parameter is NOT the number of
seconds the kernel waits but instead is the number of attempts the TCP stack
should make to complete the connection. This would indicate a value like "3" to
be much more sane than "30", which could invite abuse.

Quote below:

TCP_DEFER_ACCEPT
"Allows a listener to be awakened only when data arrives on the socket. Takes an
integer value (seconds), this can bound the maximum number of attempts TCP will
make to complete the connection. This option should not be used in code intended
to be portable."
Comment 10 dean gaudet 2007-02-05 18:01:28 UTC
(In reply to comment #9)
> The Linux tcp(7) man page indicates that the parameter is NOT the number of
> seconds... 

um:

> Quote below:
> 
> TCP_DEFER_ACCEPT
> "Allows a listener to be awakened only when data arrives on the socket. Takes an
> integer value (seconds)
                 ^^^^^^^
Comment 11 David Weekly 2007-02-06 01:27:16 UTC
Please kill me. Sorry.

(In reply to comment #10)
> (In reply to comment #9)
> > The Linux tcp(7) man page indicates that the parameter is NOT the number of
> > seconds... 
> 
> um:
> 
> > Quote below:
> > 
> > TCP_DEFER_ACCEPT
> > "Allows a listener to be awakened only when data arrives on the socket. Takes an
> > integer value (seconds)
>                  ^^^^^^^

Comment 12 Paul Querna 2007-02-18 23:09:48 UTC
(In reply to comment #3)
> Question to the BSD guys: Is it possible to set a timeout for the BSD accept
> filters accf_data and accf_http how long they should wait for a request until
> they drop the socket?

No, there isn't a way to set the timeout on the FreeBSD accept filters.
Comment 13 Philp M. Gollucci 2009-01-18 16:19:17 UTC
CC myself on FreeBSD related bugs
Comment 14 harm 2015-01-07 10:42:53 UTC
This exact problem causes havoc if you have many slow clients on slow networks (gprs).

We actually had this problem in production. (many simultanious clients  > 1000, on a single server)
We actually had a >80% unsuccessful connection attempts. This is a really hard problem to debug.

I cannot believe Apache ships with TCP_DEFER_ACCEPT on 1 sec, or even enabled at all. I don't see the possible gain to have this feature enabled.

This should be default be turned off, it has no benefits only downsides.
AcceptFilter http none
AcceptFilter https none


ref: varnish had it enabled for a while but they disabled it too [1]
ref: ubuntu ticket [2]
Can ubuntu change the default config to include:


[1] https://github.com/Movile/varnish/commit/687bacb3152ebc8b00b8dd737ef1dedb12bd4ee2
[2] https://bugs.launchpad.net/ubuntu/+source/apache2/+bug/134274?comments=all
Comment 15 Yann Ylavic 2015-01-07 12:39:59 UTC
(In reply to harm from comment #14)
> I cannot believe Apache ships with TCP_DEFER_ACCEPT on 1 sec, or even
> enabled at all.

This isn't the case anymore, the new value is 30s since 2.2.28 (and has always been 30s in 2.4.x), still hardcoded though.

By the way, TCP_DEFER_ACCEPT=1 is not really a second since TCP_SYNCNT (defaulting to sysctl's tcp_synack_retries when the option is not set like in httpd) is always honored (the final client's 3Way handshake ACK being continuously dropped during defer-accept, there is no real SYN/ACK to send after the one already sent for the SYN, so I mean the time that would have been needed by the server to send that many ACKs).

Consequently, one can also play with net.ipv4.tcp_synack_retries (or TCP_SYNCNT) to adjust the TCP_DEFER_ACCEPT timeout as needed (above 30s).

> I don't see the possible gain to have this feature enabled.

Well, the listener won't accept (spend resources for) spurious connections, which stay in kernel land.
Comment 16 Yann Ylavic 2015-01-07 12:40:31 UTC
Fiexed in 2.2.28 (r1608298).
Comment 17 harm 2015-01-07 12:57:06 UTC
(In reply to Yann Ylavic from comment #15)

> This isn't the case anymore, the new value is 30s since 2.2.28 (and has
> always been 30s in 2.4.x), still hardcoded though.

confirmed, we had these problems in 2.2.22, sorry for bringing it up again.

> Well, the listener won't accept (spend resources for) spurious connections,
> which stay in kernel land.

Well... thats whats advertised..yes.  It was somehow broken though (with a value of 1). resulting in connections not passed at all from kernel land.
So at least in 2.2.22 I doubt you'll _ever_ really see any benefits.

(we concluded this after many many hours staring at wireshark logs, with telco partner)

To mee it sounds like a fishy optimization, without (measured) benefits. maybe this made sense when linux/bsd where competing pleasing random non relevant benchmarks (a decade ago)... but I doubt this is valid nowadays.