Creation Zone

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Thursday, 12 May 2005

CPU hog with connections in CLOSE_WAIT

Posted on 15:45 by Unknown
Couple of days back I got a call at our partner's site, to look into an issue where one process (server) is hogging all the processing power with absolutely no load on the server. The server process is running on Solaris 9.

% prstat 1 1
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
2160 QAtest 941M 886M cpu0 0 0 80:03:57 99% myserver/41
28352 patrol 7888K 6032K sleep 59 0 4:49:37 0.1% bgscollect/1
24720 QAtest 1872K 1656K cpu3 59 0 0:00:00 0.0% prstat/1
59 root 4064K 3288K sleep 59 0 0:27:56 0.0% picld/6
2132 QAtest 478M 431M sleep 59 0 0:15:45 0.0% someserver.exe/901

I started off with my favorite tool truss, and found that the recv() system call is being called tons of times with no corresponding send().

% truss -c -p 2160
^Csyscall seconds calls errors
time .001 115
lwp_park .001 51 24
lwp_unpark .000 23
poll .002 34
recv 61.554 2512863
-------- ------ ----
sys totals: 61.561 2513086 24
usr time: 12.008
elapsed: 68.350

Interestingly the return value of all recv() calls is 0 (EOF). A return value of 0 is an indication that the the other end has nothing more to write and ready to close the socket (connection).

% head /tmp/truss.log
2160/216: recv(294, 0x277C9410, 32768, 0) = 0
2160/222: recv(59, 0x1F4CB410, 32768, 0) = 0
2160/216: recv(294, 0x277C9410, 32768, 0) = 0
2160/222: recv(59, 0x1F4CB410, 32768, 0) = 0
2160/216: recv(294, 0x277C9410, 32768, 0) = 0
2160/222: recv(59, 0x1F4CB410, 32768, 0) = 0
2160/216: recv(294, 0x277C9410, 32768, 0) = 0
2160/222: recv(59, 0x1F4CB410, 32768, 0) = 0
2160/216: recv(294, 0x277C9410, 32768, 0) = 0
2160/222: recv(59, 0x1F4CB410, 32768, 0) = 0
2160/216: recv(294, 0x277C9410, 32768, 0) = 0

A typical recv() call will be like this:
recv(55, 0x05CCB010, 4096, 0)                   = 2958

Then collected the network statistics, and found quite a number of connections in CLOSE_WAIT state

% netstat -an
...
127.0.0.1.54356 127.0.0.1.9810 49152 0 49152 0 ESTABLISHED
127.0.0.1.9810 127.0.0.1.54356 49152 0 49152 0 ESTABLISHED
127.0.0.1.54687 127.0.0.1.9810 49152 0 49152 0 ESTABLISHED
127.0.0.1.9810 127.0.0.1.54687 49152 0 49152 0 ESTABLISHED
...
127.0.0.1.9710 127.0.0.1.55830 49152 0 49152 0 CLOSE_WAIT
127.0.0.1.9810 127.0.0.1.57701 49152 0 49152 0 CLOSE_WAIT
127.0.0.1.9710 127.0.0.1.59209 49152 0 49152 0 CLOSE_WAIT
127.0.0.1.9810 127.0.0.1.60694 49152 0 49152 0 CLOSE_WAIT
127.0.0.1.9810 127.0.0.1.61133 49152 0 49152 0 CLOSE_WAIT
127.0.0.1.9810 127.0.0.1.61136 49152 0 49152 0 CLOSE_WAIT
...

(Later realized that these half-closed socket connections have been lying there for more than two days).
2160/216:       recv(294, 0x277C9410, 32768, 0)                 = 0 <- from truss

The next step is to find out the state of the network connection, with socket id: 294. pfiles utility of Solaris, reports the information for all open files in each process. It makes sense to use this utility, as the socket descriptor is nothing, but a file id. (On UNIX, everything is mapped to a file including the raw devices)

% pfiles 2160
2160: /export/home/QAtest/572bliss/web/bin/myserver
Current rlimit: 1024 file descriptors
...
294: S_IFSOCK mode:0666 dev:259,0 ino:35150 uid:0 gid:0 size:0
O_RDWR
sockname: AF_INET 127.0.0.1 port: 9710
peername: AF_INET 127.0.0.1 port: 59209

Now it is fairly easy to identify the connection with the port numbers reported in pfiles output

% netstat -an | grep 59209
127.0.0.1.9710 127.0.0.1.59209 49152 0 49152 0 CLOSE_WAIT

A closer look at the other socket ids from truss indicated that the server is continuously trying to read data from connections that are in CLOSE_WAIT state. Here are the corresponding statistics for TCP:
% netstat -s

TCP tcpRtoAlgorithm = 4 tcpRtoMin = 400
tcpRtoMax = 60000 tcpMaxConn = -1
tcpActiveOpens =4593219 tcpPassiveOpens =2259153
tcpAttemptFails =4036987 tcpEstabResets = 20254
tcpCurrEstab = 75 tcpOutSegs =1264739589
tcpOutDataSegs =645683085 tcpOutDataBytes =1480883468
tcpRetransSegs =682053 tcpRetransBytes =759804724
tcpOutAck =618848538 tcpOutAckDelayed =40226142
tcpOutUrg = 351 tcpOutWinUpdate =155203
tcpOutWinProbe = 3278 tcpOutControl =18622247
tcpOutRsts =8970930 tcpOutFastRetrans = 60772
tcpInSegs =1622143125
tcpInAckSegs =443838358 tcpInAckBytes =1459391481
tcpInDupAck =3254927 tcpInAckUnsent = 0
tcpInInorderSegs =1462796453 tcpInInorderBytes =550228772
tcpInUnorderSegs = 12095 tcpInUnorderBytes =10680481
tcpInDupSegs = 60814 tcpInDupBytes =30969565
tcpInPartDupSegs = 29 tcpInPartDupBytes = 19498
tcpInPastWinSegs = 66 tcpInPastWinBytes =102280302
tcpInWinProbe = 2142 tcpInWinUpdate = 3092
tcpInClosed = 1218 tcpRttNoUpdate =391989
tcpRttUpdate =441925010 tcpTimRetrans =185795
tcpTimRetransDrop = 456 tcpTimKeepalive = 8077
tcpTimKeepaliveProbe= 3054 tcpTimKeepaliveDrop = 0
tcpListenDrop = 18265 tcpListenDropQ0 = 0
tcpHalfOpenDrop = 0 tcpOutSackRetrans =255744


Apparently one end of the connection (at server, in this scenario) ignored the 0 length read (EOF) and trying to read the data from the connection as if it is still a duplex connection.

But how to check if the other end has really closed the connection?
According to man page of recv:
Upon successful completion, recv() returns the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() returns 0. Otherwise, -1 is returned and errno is set to indicate the error.

So, a simple check on the return value of recv() would do. Just to make sure that the other end is really intended to close the connection, but not sending null strings (very unlikely though), try this: after a series of EOFs (ie., return value 0) from recv(), try to write some data to the socket. It would result in a "connection reset" (ECONNRESET) error. A subsequent (second) write results in a "broken pipe" (EPIPE) error. Then it is safe to assume that the other end has closed the connection.

I just suggested the responsible engineer to check the return value of recv() and close the connection when it is safe to do so (see above).

About CLOSE_WAIT state:

CLOSE_WAIT state means the other end of the connection has been closed while the local end is still waiting for the application to close. That's normal. But an indefinite CLOSE_WAIT state normally indicates some application level bug. TCP connections will move to the CLOSE_WAIT state from the ESTABLISHED state after receiving a FIN from the remote system but before a close has called from the local application.

The CLOSE_WAIT state signifies that the endpoint has received a FIN from the peer, indicating that the peer has finished writing ie., it has no more data to send. This will be indicated by a 0 length read on the input. The connection is now half-closed or a simplex connection (one way) the receiver of the FIN still has the option of writing more data. The state can persist indefinitely as a it is perfectly valid, synchronized tcp state. The peer should be in FIN_WAIT_2 (i.e. sent fin, received ack, waiting for fin). It's only an application's fault, if the it ignores the EOF (0 length read) and persists as if the connection is still a duplex connection.

Note that an application that only intends to receive data and not send any, might close its end of the connection, which leaves the other end in CLOSE_WAIT until the process at that end is done sending data and issues a close. (But that's not the case in this scenario.)

State diagram for the closing phase of a TCP connection:

Server Client
| Fin |
CLOSE_WAIT|<-------------- | FIN_WAIT_1
| |
| Ack |
|--------------->| FIN_WAIT_2
| |
| |
| |
| |
| |
| |
| Fin |
LAST_ACK |--------------->| TIME_WAIT
| |
| Ack |
|<-------------- |
CLOSED | |
| |



Reference:
Sun Alert document:
TCP: Why do I have tcp connections in the CLOSE_WAIT state?

Suggested reading:
RFC 793 Transmission Control protocol
Email ThisBlogThis!Share to XShare to Facebook
Posted in | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • *nix: Workaround to cannot find zipfile directory in one of file.zip or file.zip.zip ..
    Symptom: You are trying to extract the archived files off of a huge (any file with size > 2 GB or 4GB, depending on the OS) ZIP file with...
  • JDS: Installing Sun Java Desktop System 2.0
    This document will guide you through the process of installing JDS 2.0 on a PC from integrated CDROM images Requirements I...
  • Linux: Installing Source RPM (SRPM) package
    RPM stands for RedHat Package Manager. RPM is a system for installing and managing software & most common software package manager used ...
  • Solaris: malloc Vs mtmalloc
    Performance of Single Vs Multi-threaded application Memory allocation performance in single and multithreaded environments is an important a...
  • C/C++: Printing Stack Trace with printstack() on Solaris
    libc on Solaris 9 and later, provides a useful function called printstack , to print a symbolic stack trace to the specified file descripto...
  • Installing MySQL 5.0.51b from the Source Code on Sun Solaris
    Building and installing the MySQL server from the source code is relatively very easy when compared to many other OSS applications. At least...
  • Oracle Apps on T2000: ORA-04020 during Autoinvoice
    The goal of this brief blog post is to provide a quick solution to all Sun-Oracle customers who may run into a deadlock when a handful of th...
  • Siebel Connection Broker Load Balancing Algorithm
    Siebel server architecture supports spawning multiple application object manager processes. The Siebel Connection Broker, SCBroker, tries to...
  • 64-bit dbx: internal error: signal SIGBUS (invalid address alignment)
    The other day I was chasing some lock contention issue with a 64-bit application running on Solaris 10 Update 1; and stumbled with an unexpe...
  • Oracle 10gR2/Solaris x64: Fixing ORA-20000: Oracle Text errors
    First, some facts: * Oracle Applications 11.5.10 (aka E-Business Suite 11 i ) database is now supported on Solaris 10 for x86-64 architectur...

Categories

  • 80s music playlist
  • bandwidth iperf network solaris
  • best
  • black friday
  • breakdown database groups locality oracle pmap sga solaris
  • buy
  • deal
  • ebiz ebs hrms oracle payroll
  • emca oracle rdbms database ORA-01034
  • friday
  • Garmin
  • generic+discussion software installer
  • GPS
  • how-to solaris mmap
  • impdp ora-01089 oracle rdbms solaris tips upgrade workarounds zombie
  • Magellan
  • music
  • Navigation
  • OATS Oracle
  • Oracle Business+Intelligence Analytics Solaris SPARC T4
  • oracle database flashback FDA
  • Oracle Database RDBMS Redo Flash+Storage
  • oracle database solaris
  • oracle database solaris resource manager virtualization consolidation
  • Oracle EBS E-Business+Suite SPARC SuperCluster Optimized+Solution
  • Oracle EBS E-Business+Suite Workaround Tip
  • oracle lob bfile blob securefile rdbms database tips performance clob
  • oracle obiee analytics presentation+services
  • Oracle OID LDAP ADS
  • Oracle OID LDAP SPARC T5 T5-2 Benchmark
  • oracle pls-00201 dbms_system
  • oracle siebel CRM SCBroker load+balancing
  • Oracle Siebel Sun SPARC T4 Benchmark
  • Oracle Siebel Sun SPARC T5 Benchmark T5-2
  • Oracle Solaris
  • Oracle Solaris Database RDBMS Redo Flash F40 AWR
  • oracle solaris rpc statd RPC troubleshooting
  • oracle solaris svm solaris+volume+manager
  • Oracle Solaris Tips
  • oracle+solaris
  • RDC
  • sale
  • Smartphone Samsung Galaxy S2 Phone+Shutter Tip Android ICS
  • solaris oracle database fmw weblogic java dfw
  • SuperCluster Oracle Database RDBMS RAC Solaris Zones
  • tee
  • thanksgiving sale
  • tips
  • TomTom
  • windows

Blog Archive

  • ►  2013 (16)
    • ►  December (3)
    • ►  November (2)
    • ►  October (1)
    • ►  September (1)
    • ►  August (1)
    • ►  July (1)
    • ►  June (1)
    • ►  May (1)
    • ►  April (1)
    • ►  March (1)
    • ►  February (2)
    • ►  January (1)
  • ►  2012 (14)
    • ►  December (1)
    • ►  November (1)
    • ►  October (1)
    • ►  September (1)
    • ►  August (1)
    • ►  July (1)
    • ►  June (2)
    • ►  May (1)
    • ►  April (1)
    • ►  March (1)
    • ►  February (1)
    • ►  January (2)
  • ►  2011 (15)
    • ►  December (2)
    • ►  November (1)
    • ►  October (2)
    • ►  September (1)
    • ►  August (2)
    • ►  July (1)
    • ►  May (2)
    • ►  April (1)
    • ►  March (1)
    • ►  February (1)
    • ►  January (1)
  • ►  2010 (19)
    • ►  December (3)
    • ►  November (1)
    • ►  October (2)
    • ►  September (1)
    • ►  August (1)
    • ►  July (1)
    • ►  June (1)
    • ►  May (5)
    • ►  April (1)
    • ►  March (1)
    • ►  February (1)
    • ►  January (1)
  • ►  2009 (25)
    • ►  December (1)
    • ►  November (2)
    • ►  October (1)
    • ►  September (1)
    • ►  August (2)
    • ►  July (2)
    • ►  June (1)
    • ►  May (2)
    • ►  April (3)
    • ►  March (1)
    • ►  February (5)
    • ►  January (4)
  • ►  2008 (34)
    • ►  December (2)
    • ►  November (2)
    • ►  October (2)
    • ►  September (1)
    • ►  August (4)
    • ►  July (2)
    • ►  June (3)
    • ►  May (3)
    • ►  April (2)
    • ►  March (5)
    • ►  February (4)
    • ►  January (4)
  • ►  2007 (33)
    • ►  December (2)
    • ►  November (4)
    • ►  October (2)
    • ►  September (5)
    • ►  August (3)
    • ►  June (2)
    • ►  May (3)
    • ►  April (5)
    • ►  March (3)
    • ►  February (1)
    • ►  January (3)
  • ►  2006 (40)
    • ►  December (2)
    • ►  November (6)
    • ►  October (2)
    • ►  September (2)
    • ►  August (1)
    • ►  July (2)
    • ►  June (2)
    • ►  May (4)
    • ►  April (5)
    • ►  March (5)
    • ►  February (3)
    • ►  January (6)
  • ▼  2005 (72)
    • ►  December (5)
    • ►  November (2)
    • ►  October (6)
    • ►  September (5)
    • ►  August (5)
    • ►  July (10)
    • ►  June (8)
    • ▼  May (9)
      • Solaris: 32-bits , fopen() and max number of open ...
      • Behavior of Sun C++ Compiler While Compiling Templ...
      • Solaris: hijacking a function call (interposing)
      • Sun C/C++: Reducing symbol scope with Linker Scopi...
      • Csh: Arguments too long error
      • CPU hog with connections in CLOSE_WAIT
      • Solaris: Mounting a CD-ROM manually
      • C/C++: global const variables, symbol collisions &...
      • C/C++: Printing Stack Trace with printstack() on S...
    • ►  April (6)
    • ►  March (6)
    • ►  February (5)
    • ►  January (5)
  • ►  2004 (36)
    • ►  December (1)
    • ►  November (5)
    • ►  October (12)
    • ►  September (18)
Powered by Blogger.

About Me

Unknown
View my complete profile