博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
记一次TIME_WAIT网络故障
阅读量:4159 次
发布时间:2019-05-26

本文共 2476 字,大约阅读时间需要 8 分钟。

from: 

临近年关,人会变得浮躁,期间写的代码可谓乱七八糟。不过出来混始终是要还的,这不最近就发现一个PHP脚本时常连不上服务器。

遇到这类问题,我习惯于先用strace命令跟踪了一下看看:

shell> strace php /path/to/fileEADDRNOTAVAIL (Cannot assign requested address)

从字面结果看似乎是网络资源相关问题。这里顺便介绍一点小技巧:在调试的时候一般是从后往前看strace命令的结果,这样更容易找到有价值的信息。

查看一下当前的网络连接情况,结果发现TIME_WAIT数非常大:

shell> netstat -nt | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'TIME_WAIT 28233

重复了几次测试,结果每次出问题的时候,TIME_WAIT都等于28233,这真是一个魔法数字!实际原因很简单,它取决于一个内核参数net.ipv4.ip_local_port_range:

shell> sysctl -a | grep portnet.ipv4.ip_local_port_range = 32768 61000

因为端口范围是一个闭区间,所以实际可用的端口数量是:

shell> echo $((61000-32767))28233

问题分析到这里基本就清晰了,解决方向也明确了,内容所限,这里就不说如何优化程序代码了,只是从系统方面来阐述如何解决问题,无非就是以下两个方面:

首先是增加本地可用端口数量。这点可以用以下命令来实现:

shell> echo "net.ipv4.ip_local_port_range = 10240 61000" >> /etc/sysctl.confshell> sysctl -p

其次是减少TIME_WAIT连接状态。网络上已经有不少相关的介绍,大多是建议:

shell> sysctl net.ipv4.tcp_tw_reuse=1shell> sysctl net.ipv4.tcp_tw_recycle=1

这两个选项在降低TIME_WAIT数量方面可以说是立竿见影,不过如果你觉得问题已经完美搞定那就错了,实际上这样可能会引入一个更复杂的网络故障。

关于内核参数的详细介绍,可以参考。我们这里简要说明一下tcp_tw_recycle参数。它用来快速回收TIME_WAIT连接,不过如果在NAT环境下会引发问题。

中有如下一段描述:

An additional mechanism could be added to the TCP, a per-host cache of the last timestamp received from any connection. This value could then be used in the  mechanism to reject old duplicate segments from earlier incarnations of the connection, if the timestamp clock can be guaranteed to have ticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT together must be at least one tick of the sender’s timestamp clock. Such an extension is not part of the proposal of this RFC.

大概意思是说TCP有一种行为,可以缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。

Linux是否启用这种行为取决于tcp_timestamps和tcp_tw_recycle,因为tcp_timestamps缺省就是开启的,所以当tcp_tw_recycle被开启后,实际上这种行为就被激活了。

现在很多公司都用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,这其实就是NAT,当请求到达LVS后,它修改地址数据后便转发给后端服务器,但不会修改时间戳数据,对于后端服务器来说,请求的源地址就是LVS的地址,加上端口会复用,所以从后端服务器的角度看,原本不同客户端的请求经过LVS的转发,就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象:

shell> netstat -s | grep timestamp... packets rejects in established connections because of timestamp

结论显而易见:如果服务器身处NAT环境,一定要禁止tcp_tw_recycle,至于TIME_WAIT连接过多的问题,可以通过激活tcp_tw_reuse来缓解(暂未发现副作用)。

再唠十块钱儿的,既然必须同时激活tcp_timestamps和tcp_tw_recycle才会触发这种现象,那能不能禁止tcp_timestamps,激活tcp_tw_recycle,这样既可以避免激活丢包问题,又可以降低TIME_WAIT连接数量。可惜很多服务依赖tcp_timestamps。

老实说,这次网络故障本身并没什么高深之处,不过拔出萝卜带出泥,在过程中牵扯的方方面面还是值得大家仔细体会的,于是便有了这篇文字。

转载地址:http://skbxi.baihongyu.com/

你可能感兴趣的文章
李开复:移动互联网机会最大 微博会现最大赢家
查看>>
2006年的IT十大战略技术
查看>>
操作系统介绍
查看>>
Desktop Linux: The Dream Is Dead
查看>>
我的9年IT路
查看>>
任正非:让用户像用电一样享受云计算
查看>>
学习技术的几个境界
查看>>
计算机世界:免费的代价
查看>>
方兴东:中国网站十年
查看>>
2010年微软和谷歌十大战场:从桌面到浏览器
查看>>
马云给阿里巴巴员工的公开信
查看>>
服务器虚拟化的未来之路
查看>>
写给我们这些浮躁的系统工程师
查看>>
和平分手?你根本不知道吴恩达在百度经历了什么
查看>>
业余研究:关于腾讯与他的QQ帝国
查看>>
马云校长湖畔大学第三期讲义完整版
查看>>
iPhone为什么比Android好
查看>>
小程序的今天就是微信指数的明天
查看>>
从互联网到人工智能,BAT这七年来到底做了什么
查看>>
2012年十大科技趋势:Siri将震惊世界
查看>>