linux下建立tcp连接(connect)非常慢的问题的排查

先说结论:
执行了如下的命令后,问题解决。 之前nf_conntrack_max的值是65536
sysctl -w net.netfilter.nf_conntrack_max=358576


参考:

Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论

http://www.sdnlab.com/17530.html

===================================

问题描述:

 当php的请求量稍微变大的时候(nginx+php-fpm的架构),php对外建立连接的时间 connnect 的时间会变长(无论连接mysql,还是redis都很慢),持续几秒钟才建立了解成功,有的时候甚至卡10几秒,30秒,但是本身请求量不是非常大,也就几百次/秒,同时cpu占用非常低(10%不到), time_wait连接数也很少(开启了快速回收),进程能打开的句柄数8192(和打开的fd数量没关系),机器的网络流量也远没有达到瓶颈(实际上这个机器时不限制流量上限的),那么问题出在哪里了?

机器:
12核12G,php-frm 400个进程。

strace php进程看到的一些现象:

//  这个是异常的情况 
 1476414907.830951 connect(5, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("10.66.112.169")}, 16) = -1 EINPROGRESS (Operation now in progress)
1476414907.830985 poll([{fd=5, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, -1000) = 1 ([{fd=5, revents=POLLOUT}])
1476414910.831337 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0  // 这里poll了3秒才返回 

// 这个是正常的情况 

 1476415329.443653 connect(5, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("10.66.112.169")}, 16) = -1 EINPROGRESS (Operation now in progress)
1476415329.443697 poll([{fd=5, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, -1000) = 1 ([{fd=5, revents=POLLOUT}])
1476415329.443953 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0  // 压力小点的时候,很快就返回了。 

===================================

排查过程:

起初怀疑是机器问题,但是试了很多台机器,都有一样的现象。

再次怀疑是redis或者mysql服务器的问题,但是当把请求分担到很多个机器上,即使总的请求量很大的时候,redis和mysql也正常服务

其次怀疑代码问题
       1 怀疑thinkphp框架有什么问题,至少发现 /var/lib/php/session/目录下回频繁的创建sess文件,几十万个,都是我们没用的东西,正好本身觉得用框架效率也低(框架里面的功能都是我们用不着的),就把代码重构去掉了框架。 没有了sess文件之后,问题依旧。

       2 既然connect频繁了会有问题,那我不用短连接总可以了吧,把redis和mysqli都是用长连接后,症状轻了点,支持的请求数翻了2倍,也不过400左右,更高的时候问题又出现了

      3 当redis和mysql都是长连接后,php访问腾讯的openapi依然还是短连接,这个依然会connect会卡!但是腾讯的openapi是之前在腾讯的时候自己做的,很多开发商在用,很明确的是没有问题的,一定是问题出在我们身上。 当connect卡的时候, telnet openapi.tencentyun.com 80 也是不定时的telnet不通,或卡一段时间。 既然telnet都卡了,应该和代码没关系了吧。

最后怀疑是机器的某些tcp相关内核参数配置的问题

网上搜索了下 tcp 丢包,发现了答案

       http://www.sdnlab.com/17530.html

       Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论


我的机器上执行 dmesg 结果如下;

[4331898.853374] __ratelimit: 5 callbacks suppressed

[4331898.853378] nf_conntrack: table full, dropping packet.
[4331898.914146] nf_conntrack: table full, dropping packet.
[4331898.914380] nf_conntrack: table full, dropping packet.
[4331899.047487] nf_conntrack: table full, dropping packet.
[4331899.047501] nf_conntrack: table full, dropping packet.
[4331899.047508] nf_conntrack: table full, dropping packet.
[4331899.047515] nf_conntrack: table full, dropping packet.
[4331899.047525] nf_conntrack: table full, dropping packet.
[4331899.047532] nf_conntrack: table full, dropping packet.
[4331899.047539] nf_conntrack: table full, dropping packet.

。。。。。


# 查看nf_conntrack表最大连接数
$ cat /proc/sys/net/netfilter/nf_conntrack_max
65536
# 查看nf_conntrack表当前连接数 已经满了,或者接近满了(是个动态变化的值)
$ cat /proc/sys/net/netfilter/nf_conntrack_count
65535

根据文中的指引调大  /proc/sys/net/netfilter/nf_conntrack_max 之后,问题解决。 cpu的压力上来了,php进程不再阻塞。

你可能感兴趣的:(tcp/ip,linux)