TCP的CLOSE_WAIT和TIME_WAIT问题汇总
线上环境挂了,咋整?排查思路:是不是特例还是所有情况下的数据都获取不到?是不是网络断了(比如某厂的光缆又断了?)是不是服务停了 (Sig 11?OOM?或者core dump)是不是应用服务器都CPU 100%了?看看监控系统有没有报警? (当然得有对吧)看看DB是不是被人删了?(进过某旅游网站的事件后,这总也是一种可能行对吧)有云监控,可以看下SLB的心跳还活着,排除网络问题所有服务器的CPU/
线上环境挂了,咋整?
排查思路:
-
是不是特例还是所有情况下的数据都获取不到?
-
是不是网络断了(比如某厂的光缆又断了?)
-
是不是服务停了 (Sig 11?OOM?或者core dump)
-
是不是应用服务器都CPU 100%了?
-
看看监控系统有没有报警? (当然得有对吧)
-
看看DB是不是被人删了?(进过某旅游网站的事件后,这总也是一种可能行对吧)
有云监控,可以看下
-
SLB的心跳还活着,排除网络问题
-
所有服务器的CPU/Memory/IO都还正常没有峰值
-
关键进程还在
-
DB也还健在(还好 还好)
排查NGINX日志
- resp_time和upstream_time响应时间
- wirashark分析,tcpdump tcp port 80 -w staging.pcap
- watch -d -n1 ‘netstat -s | grep reset’
SSH上去看系统
- “先听听操作系统的声音,让操作系统来告诉你问题在哪”
- 从网络开始,netstat -anp tcp 查看tcp连接状态分布
- Foreign Address,这个就是代表对方的IP地址
TCP参数配置
net.ipv4.tcp_timestamps
RFC 1323 在 TCP Reliability一节里,引入了timestamp的TCP option,两个4字节的时间戳字段,其中第一个4字节字段用来保存发送该数据包的时间,第二个4字节字段用来保存最近一次接收对方发送到数据的时间。有了这两个时间字段,也就有了后续优化的余地。
tcp_tw_reuse 和 tcp_tw_recycle就依赖这些时间字段。
net.ipv4.tcp_tw_reuse
字面意思,reuse TIME_WAIT状态的连接。
时刻记住一条socket连接,就是那个五元组,出现TIME_WAIT状态的连接,一定出现在主动关闭连接的一方。所以,当主动关闭连接的一方,再次向对方发起连接请求的时候(例如,客户端关闭连接,客户端再次连接服务端,此时可以复用了;负载均衡服务器,主动关闭后端的连接,当有新的HTTP请求,负载均衡服务器再次连接后端服务器,此时也可以复用),可以复用TIME_WAIT状态的连接。
通过字面解释,以及例子说明,你看到了,tcp_tw_reuse应用的场景:某一方,需要不断的通过“短连接”连接其他服务器,总是自己先关闭连接(TIME_WAIT在自己这方),关闭后又不断的重新连接对方。
那么,当连接被复用了之后,延迟或者重发的数据包到达,新的连接怎么判断,到达的数据是属于复用后的连接,还是复用前的连接呢?那就需要依赖前面提到的两个时间字段了。复用连接后,这条连接的时间被更新为当前的时间,当延迟的数据达到,延迟数据的时间是小于新连接的时间,所以,内核可以通过时间判断出,延迟的数据可以安全的丢弃掉了。
这个配置,依赖于连接双方,同时对timestamps的支持。同时,这个配置,仅仅影响outbound连接,即做为客户端的角色,连接服务端[connect(dest_ip, dest_port)]时复用TIME_WAIT的socket。
net.ipv4.tcp_tw_recycle
字面意思,销毁掉 TIME_WAIT。
当开启了这个配置后,内核会快速的回收处于TIME_WAIT状态的socket连接。多快?不再是2MSL,而是一个RTO(retransmission timeout,数据包重传的timeout时间)的时间,这个时间根据RTT动态计算出来,但是远小于2MSL。
有了这个配置,还是需要保障 丢失重传或者延迟的数据包,不会被新的连接(注意,这里不再是复用了,而是之前处于TIME_WAIT状态的连接已经被destroy掉了,新的连接,刚好是和某一个被destroy掉的连接使用了相同的五元组而已)所错误的接收。在启用该配置,当一个socket连接进入TIME_WAIT状态后,内核里会记录包括该socket连接对应的五元组中的对方IP等在内的一些统计数据,当然也包括从该对方IP所接收到的最近的一次数据包时间。当有新的数据包到达,只要时间晚于内核记录的这个时间,数据包都会被统统的丢掉。
这个配置,依赖于连接双方对timestamps的支持。同时,这个配置,主要影响到了inbound的连接(对outbound的连接也有影响,但是不是复用),即做为服务端角色,客户端连进来,服务端主动关闭了连接,TIME_WAIT状态的socket处于服务端,服务端快速的回收该状态的连接。
由此,如果客户端处于NAT的网络(多个客户端,同一个IP出口的网络环境),如果配置了tw_recycle,就可能在一个RTO的时间内,只能有一个客户端和自己连接成功(不同的客户端发包的时间不一致,造成服务端直接把数据包丢弃掉)。
查看TCP连接状态脚本
|
优化的LINUX网络配置建议
vi /etc/sysctl.conf net.ipv6.conf.all.disable_ipv6 =1 net.ipv4.conf.all.arp_announce=2 net.ipv4.conf.lo.arp_announce=2 fs.file-max=65535 net.core.netdev_max_backlog=30000 net.core.somaxconn=10000 net.core.rps_sock_flow_entries=32768 net.ipv4.tcp_max_syn_backlog=10000 net.ipv4.tcp_max_tw_buckets=10000 net.ipv4.tcp_fin_timeout=10 net.ipv4.tcp_timestamps=1 net.ipv4.tcp_tw_recycle=0 net.ipv4.tcp_tw_reuse=0 net.ipv4.tcp_synack_retries=2 net.ipv4.tcp_window_scaling=1 net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_intvl=30 net.ipv4.tcp_keepalive_probes=5 net.core.wmem_default=8388608 net.core.rmem_default=8388608 net.core.rmem_max=16777216 net.core.wmem_max=16777216 net.ipv4.tcp_syncookies=1 net.ipv4.tcp_mem=94500000915000000 927000000 net.ipv4.tcp_max_orphans=3276800 net.ipv4.ip_local_port_range=102465535 |
FAQ
SLB 作为负载均衡,基本没有业务逻辑,那它会主动关闭连接的场景有哪些?
-
进程退出(正常或者非正常)
-
TCP 连接超时
为啥一台机器区区几百个close_wait就导致不可继续访问?不合理啊,一台机器不是号称最大可以开到65535个端口吗?
-
Tornado是单进程启动的服务,所以IOLoop也就一个实例在监听并轮询
-
Tornado在bind每个socket的时候有默认的链接队列(也叫backlog)为128个
-
由于代码错误,我们使用了同步库urllib2 做第三方请求,导致访问第三方的时候当前RequestHandler是同步的(yield不起作用),因此当IOLoop回调这个RequestHandler时会等待它返回
-
第三方接口真的不快!
[回答]: 由于原因#4和#3所以导致整个IOLoop慢了,进而因为#2 导致很多请求堆积,也就是说很多请求在被真正处理前已经在backlog里等了一会了。
导致了SLB这端的链接批量的超时,同时又由于close_wait状态不会自动消失,导致最终无法再这个端口上创建新的链接引起了停止服务
为啥明明有多个服务器承载,却几乎同时出了close_wait? 又为什么同时不能再服务?那要SLB还有啥用呢
[回答]: 有了上一个答案,结合SLB的特性,这个也就很好解释。
这就是所谓的洪水蔓延,当SLB发现下面的一个节点不可用时会吧请求routing到其他可用节点上,导致了其他节点压力增大。也犹豫相同原因,加速了其他节点出现close_wait.
所说连接池可以复用连接,是不是意味着,需要等到上个连接time wait结束后才能再次使用?
[回答]:
所谓连接池复用,复用的一定是活跃的连接,所谓活跃,
第一表明连接池里的连接都是ESTABLISHED的,
第二,连接池做为上层应用,会有定时的心跳去保持连接的活跃性。既然连接都是活跃的,那就不存在有TIME_WAIT的概念了,TIME_WAIT是在主动关闭连接的一方,在关闭连接后才进入的状态。既然已经关闭了,那么这条连接肯定已经不在连接池里面了,即被连接池释放了。
作为负载均衡的机器随机端口使用完的情况下大量time_wait,不调整文字里说的那三个参数,有其他的更好的方案吗?
[回答]:
第一,随机端口使用完,你可以通过调整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成 net.ipv4.ip_local_port_range=1024 65535,保证你的负载均衡服务器至少可以使用6万个随机端口,也即可以有6万的反向代理到后端的连接,可以支持每秒1000的并发(想一想,因为TIME_WAIT状态会持续1分钟后消失,所以一分钟最多有6万,每秒1000);
如果这么多端口都使用完了,也证明你应该加服务器了,或者,你的负载均衡服务器需要配置多个IP地址,或者,你的后端服务器需要监听更多的端口和配置更多的IP(想一下socket的五元组)
第二,大量的TIME_WAIT,多大量?如果是几千个,其实不用担心,因为这个内存和CPU的消耗有一些,但是是可以忽略的。
第三,如果真的量很大,上万上万的那种,可以考虑,让后端的服务器主动关闭连接,如果后端服务器没有外网的连接只有负载均衡服务器的连接(主要是没有NAT网络的连接),可以在后端服务器上配置tw_recycle,然后同时,在负载均衡服务器上,配置tw_reuse。
因为TIME_WAIT状态会持续1分钟后消失,所以一分钟最多有6万,每秒1000,为什么?
[回答]: 这个问题还没找到
参考链接
https://mp.weixin.qq.com/s/5S39zO3jrsQC1QwC1yye_A
https://mp.weixin.qq.com/s/AkWEQtcYYaWsE6VzHny5sw
https://mp.weixin.qq.com/s/AQrx06StJ6p4fY0bD6faqA
更多推荐
所有评论(0)