python 解决close_wait过多问题

2 篇文章 0 订阅
1 篇文章 0 订阅

最近在公司遇到CLOSE_WAIT过多的问题,现在解决后总结下,先说下CLOSE_WAIT产生的原因:

首先要知道客户端和服务端的连接是使用套接字通信的,TCP/IP协议建立连接需要三次握手,而关闭client与server的连接需要进行四步,如图:


建立连接后常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

通过上图,我们来分析,什么情况下,连接处于CLOSE_WAIT状态呢?

        就是服务端在被动关闭收到FIN,未发出自己FIN的情况下就处于CLOSE_WAIT状态了,通常CLOSE_WAIT的持续时间很

短,但是在某些特殊状态下就可能长时间存在,如果出现大量close_wait的现象,主要原因可能是一方关闭了socket链接,但是另一方

忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno( errno 是记录系统的最后

一次错误代码。),如果不是AGAIN,就断开连接。

在linux中查看socket状态的命令:

    netstat -nt | awk '{wait[$NF]++}END{for(i in wait) print i,wait[i]}'

得到如下结果:

                           

然后查看处于CLOSE_WAIT的都是哪些端口:

    netstat -nt | awk '{if($NF=="CLOSE_WAIT"){wait[$5]++}}END{for(i in wait) print i,wait[i]}'

得到如下结果:

                          

第一条命令会把当前所有的状态进行分类,第二个命令,他会定位到具体出问题的端口,再根据端口找到相应的程序,修改相应的程序即可。

        上面还提到一种状态就是TIME_WAIT ,如果TIME_WAIT过多,也会对系统造成影响。TIME_WAIT 和CLOSE_WAIT过多

都会影响系统的扩展性,影响用户请求、其他系统对本系统的访问,这两种状态过多产生的影响一致,但不可用同样的方法去

解决,CLOSE_WAIT的情况需要从程序本身出发,而TIME_WAIT更倾向于修改系统参数。

   TIME_WAIT产生的原因第一张图中已经说明了,是主动关闭的一方所处的状态,然后在保持这个状态2MSL(max segment lifetime)时间之

后,彻底关闭回收资源。为什么要等2MSL的时间呢?这是TCP/IP的设计者规定的,主要出于以下两个方面的考虑:

  1.防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)
  2.可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就

     会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很

     大资源的,除非短时间内接受大量请求或者受到攻击。


解决思路很简单,就是让服务器能够快速回收和重用那些TIME_WAIT的资源。

下面我们来看一下/etc/sysctl.conf文件的配置:

<pre name="code" class="plain">#表示开启重用。允许将TIME_WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
1、net.ipv4.tcp_tw_reuse = 1

#表示开启TCP连接中TIME_WAIT sockets的快速回收,默认为0,表示关闭
2、net.ipv4.tcp_tw_recycle = 1

#<span style="font-family:FangSong_GB2312;">表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN_WAIT_2状态的时间(可改为30,一般来说FIN_WAIT_2的连接也极少)</span>
3、net.ipv4.tcp_fin_timeout = 30

#<span style="font-family:SimHei;color:#333333;LINE-HEIGHT: 22px;">控制 TCP/IP 尝试验证空闲连接是否完好的频率</span>
4、net.ipv4.tcp_keepalive_time = 600

#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
5、net.ipv4.tcp_max_syn_backlog = 8192 

#表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默认为180000,改为60000。
6、net.ipv4.tcp_max_tw_buckets = 60000

#记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。
7、net.ipv4.tcp_max_syn_backlog = 65536

#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
8、net.core.netdev_max_backlog = 32768

#web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。
9、net.core.somaxconn = 32768

#定义默认的发送窗口大小;对于更大的 BDP 来说,这个大小也应该更大。
10、net.core.wmem_default = 8388608

#该文件指定了接收套接字缓冲区大小的缺省值(以字节为单位)。
11、net.core.rmem_default = 8388608

#最大socket读buffer。
12、net.core.rmem_max = 16777216

#最大socket写buffer。
13、net.core.wmem_max = 16777216

#为了打开对端的连接,内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。
14、net.ipv4.tcp_synack_retries = 2

#对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右时间。
15、net.ipv4.tcp_syn_retries = 2 

#表示开启TCP连接中TIME-WAITsockets的快速回收,默认为0,表示关闭
16、net.ipv4.tcp_tw_recycle = 1

#开启重用。允许将TIME-WAITsockets重新用于新的TCP连接。
17、net.ipv4.tcp_tw_reuse = 1

#同样有3个值,意思是:低于第一个值,TCP没有内存压力;在第二个值下,进入内存压力阶段;高于第三个值,TCP拒绝分配socket(内存单位是页)。
18、net.ipv4.tcp_mem = 94500000 915000000 927000000

#系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。
19、net.ipv4.tcp_max_orphans = 3276800

#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
20、net.core.netdev_max_backlog = 8096

#表示开启SYNCookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭。
21、net.ipv4.tcp_syncookies = 1
 


上面这些参数,如1、2、3、6、14、15、16、17等和CLOSE_WAIT或TIME_WAIT有关,优化相关参数让服务跑的更好。


名词解释:

套接字:源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。其用于标识客户端请求的服务器和服务。套接字,是支持TCP/IP网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值