[erlang-questions] R13B02 on 8/16 core box: all TCP communication hangs/frozen
Luke Gorrie
luke@REDACTED
Thu Nov 19 15:35:00 CET 2009
2009/11/19 Scott Lystig Fritchie <fritchie@REDACTED>:
> Yes, I agree with your blame pointed at the kernel, but ... those
> sockets have a listen backlog of 4096. Strace shows no VM activity in
> any thread when a new TCP connection is actually established. My guess
> is that when the app does not bother calling accept(2), and then the
> listen backlog queue is full, the kernel will wait until one of the
> existing 4096 TCP connections leaves CLOSE_WAIT state, which then leaves
> an open slot in the listen queue?
Oh yes! The slow connection setup can be perfectly explained by the
application not calling accept() often enough and the listen backlog
becoming full. I just didn't understand the normal kernel behaviour
with a full backlog. Hope I didn't distract you too much :-)
FWIW I did a small experiment just to understand how Linux handles
backlogged listen sockets better. I used a debian 2.6.26-2-amd64
kernel with default settings on the server side (no special features
like SYN cookies enabled).
I started a server with a 30 connection backlog and never calling accept():
server> gen_tcp:listen(9999, [{backlog,30}]).
{ok,#Port<0.444>}
Then on the client I opened 100 connections with netcat:
client$ for i in $(seq 1 100); do (nc -w 180 server 9999 &); done
and waited a few seconds for everything to settle and then ran netstat
to see what sockets were open on each host:
server$ netstat -an | grep 9999 | awk '{print $NF}' | sort | uniq -c | sort -n
1 LISTEN
29 SYN_RECV
31 ESTABLISHED
client$ netstat -an | grep 9999 | awk '{print $NF}' | sort | uniq -c | sort -n
40 SYN_SENT
60 ESTABLISHED
So the kernel has allowed 31 (BACKLOG+1?) connections to become
ESTABLISHED and a further 29 (BACKLOG-1?) to enter SYN_RECV and seems
to have ignored the other 40 connection requests. The client sees a
full 60 connections in ESTABLISHED state (the server's ESTABLISHED +
SYN_RECV) and the rest in SYN_SENT still resending their SYN packets.
If I wait for an application timeout in netcat to close the sockets on
the client side then the server looks like this:
server$ netstat -an | grep 9999 | awk '{print $NF}' | sort | uniq -c | sort -n
1 LISTEN
31 CLOSE_WAIT
Looks like the SYN_RECV sockets were discarded and the ESTABLISHED
transitioned into the half-closed CLOSE_WAIT state. So if the server
does start calling accept() it'll process 31 sockets that are already
closed by the client. (Fair enough.)
The SYN_RECV sockets make me curious. Linux seems to have a second
backlog queue for when the normal one fills up. Connections in this
queue seem to send a SYN+ACK (because the client reaches ESTABLISHED)
but wait in SYN_RECV. The code in net/ipv4/tcp_ipv4.c's
tcp_v4_conn_request refers to this as a "syn queue" containing "warm
entries", but I haven't dug deep enough to see how it really works.
Does anyone know? (Per Hedeland? :-))
I posted a tcpdump at http://fresh.homeunix.net/~luke/misc/9999.pcap
in case anyone else is having a "geek out on Linux networking" week.
Cheers,
-Luke
More information about the erlang-questions
mailing list