之前一直没怎么关注过TCP,直到公司这次的事件,这才开始慢慢去研究,去学习TCP的相关知识,中间也尝试了很多方法,走了很多弯路,因此记下这篇文章,方便以后回顾


首先说下网络架构

记一次服务器timewait事件_第1张图片


Nginx和jetty都在同一个服务器,Nginx代理HTTP流量至多个jetty应用,基本情况就是这样


首先我们来看下,为什么会有TIMEWAIT的状态

客户端主动关闭连接时,会发送最后一个ack后,然后会进入TIME_WAIT状态,再停留2个MSL时间,进入CLOSED状态。

也就是说一般timewait只会出现在client中(因为主动关闭),server端是不会关闭连接的(以为一直在监听)


基于此,我查看了服务器的情况

发现nginx对外的tcp连接数状态是正常的,问题就在对于jetty的连接数异常的多,并且不释放


首先度娘解决方法,基本得到的结果基本就是一个修改内核参数(不推荐此做法)

net.ipv4.tcp_tw_reuse = 1 

#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭 

net.ipv4.tcp_tw_recycle = 1

#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭  

这样是可以快速的的回收socket,但是后来查询资料发现这样做有隐患

1.对于net.ipv4.tcp_tw_recycle ,Linux内核文档中实战和么描述的

tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)[译者注:来自linux man tcp的描述]

Enable fast recycling of TIME-WAIT sockets. Enabling this option is not recommended since this causes

problems when working with NAT (Network Address Translation).

启用TIME-WAIT状态sockets的快速回收,这个选项不推荐启用。在NAT(Network Address Translation)网络下,会导致大量的TCP连接建立错误。

2.有些文档中也说了对于手机端wifi访问的话,也会有问题,因为wifi端访问时间戳会乱跳,导致访问拒绝

基于以上2个隐患,所以没有使用此方法。


后来我再观察的时候,我发现nginx和jetty之间的连接大多都是短连接(因为默认nginx也是使用短连接),所以有可能是nginx作为client会快速释放,所以导致nginx的socket一直都是出于timewait状态,所以去nginx官网查看资料,配置nginx在负载均衡的时候使用长连接


具体配置为:

upstream localhost{          

……

keepalive 30;

  }

location / {

               ……           

            proxy_http_version 1.1;

            proxy_set_header Connection "";

        }

在server 的location模块里面 添加以上信息。

    注意:需要设置nginx 代理请求的 http 协议版本号为 1.1,  以及清除掉 Connection 请求header

官方文档描述:

For HTTP, the proxy_http_version directive should be set to “ 1.1 ”  and the  “Connection ”  header field should be cleared 

因为http协议1.1默认就使用长连接,所以不需要Connection的头部信息,这样打开nginx和jetty之间的长连接之后,timewait的状态大量减少。


总结:我们在遇到问题的时候,百度遇到的解决方案一定要仔细分析,千万不能随随便便就使用,因为别人的环境跟你的有可能不一样,即便当时能够解决问题,后面引发的问题,可能更加难以发现和解决。

还有我们遇到问题要多想,千万不能自以为是什么什么原因,要有事实依据,才能找到更好的解决方案

最后欢迎大家一起交流和学习。