Apache 压力测试后的大量本地连接

背景

在对Apache(prefork多进程模式)进行压力测试对时候, 客户端IP:192.168.41.96 网关IP和端口; 0.0.0.0:447 发现一旦停止压力测试对时候。 使用 netstat -an | grep 127 会出现非常多的 127.0.0.1:447 连接

tcp        0      0 127.0.0.1:38984         127.0.0.1:447           TIME_WAIT
tcp        0      0 127.0.0.1:38994         127.0.0.1:447           TIME_WAIT

查看的时候连接都已经是 TIME_WAIT 的状态,无法查看它是通过哪些进程查看它建立连接。 我们怀疑这些连接可能对性能会有影响。 所以对这个问题进行了排查。

问题解决

因为所有的127.0.0.1的端口都与447端口断开连接,又因为这些无法有效都用gdb调试。 所以使用 strace 的方式跟踪进程。

strace -p 683 -o filename_childpid strace -p 899 -o filename_masterpid

filename_childpid 是在压力测试的时候临时创建出来的子进程 filename_masterpid 是Apache的主进程

在压力测试时候出现的子进程中可以看到

accept(3, {sa_family=AF_INET, sin_port=htons(36448), sin_addr=inet_addr("127.0.0.1")}, [16]) = 6
getsockname(6, {sa_family=AF_INET, sin_port=htons(447), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0

发现这个子进程是accept了连接。但是这些环回地址是如何产生的?

查看主进程的 strace 文件

waitpid(-1, 0xbffffa18, WNOHANG|WUNTRACED) = 0
select(0, NULL, NULL, NULL, {1, 0})     = 0 (Timeout)
write(5, "!", 1)                        = 1
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 9
fcntl64(9, F_GETFL)                     = 0x2 (flags O_RDWR)
fcntl64(9, F_SETFL, O_RDWR|O_NONBLOCK)  = 0
connect(9, {sa_family=AF_INET, sin_port=htons(447), sin_addr=inet_addr("0.0.0.0")}, 16) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=9, events=POLLOUT, revents=POLLOUT}], 1, 3000) = 1
getsockopt(9, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
close(9)                                = 0
--- SIGCHLD (Child exited) @ 0 (0) ---

从这里发现Apache的主进程发了connect连接,然后自己断开连接。 但是为什么回出现这种情况呢?需要进一步查看代码查找原因。

原因

压力测试的时候起了非常多的子进程。 但是压力测试之后不需要那么多的进程。 此时临时建立的子进程都阻塞在select上面。 Apache采用都策略就是主进程与阻塞都子进程建立连接, 然后关闭连接,所以看到都现象如上。