tcp释放连接的close_wait, FIN_WAIT2, TIME_WAIT大量存在的原因及解决办法

存在close_wait的原因和解决办法

close_wait这个状态存在于服务端,当服务端发送FIN(之前客户端已经发送过fin),请求关闭连接之后进入close_wait,然而没有收到客户端的响应,可能由于客户端掉线了(如网络故障或者掉电),没有及时给予客户端回复造成问题。
或者由于客户端已经调用close(socket)退出,而服务端对其监测并断开连接,这种是服务端问题。

解决方法:一般是编程问题,可用keep_alive机制加以解决

存在FIN_WAIT2的原因和解决办法

这个状态存在于主动发起断开请求的一端,如果服务器存在大量的这个状态,那么这个服务器就充当客户端的角色,如网络爬虫,出现的原因是由于客户端发起FIN请求结束连接之后,收到了服务端的应答之后进入FIN_WAIT2,之后就没收到服务端发送的FIN信号导致。
解决方法:可以配置FIN_WAIT2的时长,当超过时长后自动断开加以解决(/proc/sys/net/ipv4/tcp_fin_timeout参数)

存在TIME_WAIT的原因和解决办法

为什么要经过TIME_WAIT状态后才真正关闭连接?
这个有两个原因:其一是响应服务端发送的FIN报文,保证服务端断开连接;其二是保证之前请求断开连接的请求,由于网络原因滞留在网络中,后续又到达了,导致后面重新建立的连接断开。

time_wait大量存在问题的原因:time_wait状态存在于主动关闭连接的一端(即客户端),如果是time_wait状态太多了,那肯定是客户端程序有问题,一般属于客户端频繁的往服务端发请求,如运行网络爬虫的机器上处于time_wait状态的socket会比较多
解决方法:可以通过修改系统配置和客户端程序解决
说明:

  1. time_wait相关的内核参数有下面几个:

    root@ /proc/sys/net/ipv4]$ ls |grep tw
    tcp_max_tw_buckets
    tcp_tw_ignore_syn_tsval_zero
    tcp_tw_recycle
    tcp_tw_recycle_private_only
    tcp_tw_reuse  
    tcp_tw_timeout #系统回收timewait状态的socket的时长
    

    这些参数的含义可以通过man tcp查看,下面仅贴出部分参数的说明:

    tcp_max_tw_buckets (integer; default: see below; since Linux 2.4)
                  The  maximum  number  of  sockets  in TIME_WAIT state allowed in the system.  This limit exists only to prevent simple denial-of-service attacks.  The default  value of NR_FILE*2 is adjusted depending on the memory in the system.  If this number is exceeded, the socket is closed and a warning is printed.
                  
    tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)
                  Enable fast recycling of TIME_WAIT sockets.  Enabling this option  is  not  recom-mended  since this causes problems when working with NAT (Network Address Transla-tion).
    
    tcp_tw_reuse (Boolean; default: disabled; since Linux 2.4.19/2.6)
                  Allow to reuse TIME_WAIT sockets for new connections when it is safe from protocol viewpoint. It should not be changed without advice/request of technical experts.
                  
    

    可以调整tcp_tw_timeout,tcp_tw_reuse参数来快速回收tcp TIME_WAIT状态的socket(不建议调整tcp_tw_recycle选项快速回收)

  2. 调整客户端程序,采取一些限频措施(可以使用连接池,缓存等技术,以减少客户端发起的请求数)

处理这类问题的实用命令

  • netstat
    用netstat命令可以查看系统的socket存在情况

    #netstat -tan|awk '$1~/tcp/{print $NF}'|sort|uniq -c|sort -nr
    156  TIME_WAIT
    141  FIN_WAIT2
    80  ESTABLISHED
    10  LISTEN
    3 CLOSE_WAIT
    2 LAST_ACK
    
  • ss
    通过ss命令我们可以看到timer的内部状态,以便用于确认处于WAIT状态socket是否被正常回收掉了。其实这边用ss也可以替代netstat来排查问题。
    查看man ss:

    SS(8)
    
    NAME
           ss - another utility to investigate sockets
    
    SYNOPSIS
           ss [options] [ FILTER ]
    
    DESCRIPTION
           ss  is  used to dump socket statistics. It allows showing information similar to netstat.  It can
           display more TCP and state informations than other tools.
    

    从man说明中可以知道这是一个可以查看socket信息的工具,和netstat类似,可以显示更详细的tcp状态信息。常用的option有:

    -a: 显示所有
    -l: 仅显示listening状态的
    -p: 
    -t|-u|-w|-x:仅显示tcp|udp|raw|unix类型的socket信息
    --socket=QUERY:按类型过滤,其中QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]
    -D, --diag=FILE : 输出到文件(Dump raw information about TCP sockets to FILE)
    -o, --options: 用于显示timer的状态(show timer information),常和state一起使用,用于查看某个state相关的timer,state有:all,syn-send,syn-recv,established,last-ack,listening,close-wait,time-wait,connected,fin-wait-{1,2},closeing,closed等等
    -s, --summary: 显示socket使用概况(show socket usage summary)
    

    其中一些示例如下:

    # ss -s
    Total: 647 (kernel 0)
    TCP:   165 (estab 60, closed 83, orphaned 0, synrecv 0, timewait 60/0), ports 0
    
    Transport Total     IP        IPv6
    *         0         -         -        
    RAW       2         1         1        
    UDP       16        16        0        
    TCP       82        82        0        
    INET      100       99        1        
    FRAG      0         0         0        
    
    # ss -o state time-wait 
    Recv-Q Send-Q                        Local Address:Port                            Peer Address:Port   
    0      0                               192.168.1.55:39003                            192.168.1.55:23001    timer:(timewait,45sec,0)
    
    其中, ss state {state_value}
    state_value有如下选项可用:
    syn-sent 发送同步信号
    syn-recv 接收同步信号
    established	建立连接
    fin-wait-{1,2}	等待 完成	2
    time-wait	等待时间	2
    closed	关闭	111
    Close-wait	等待关闭	2
    Last-ack	最后确认
    listening 坚听	32
    closing	关闭	1
    
    all : 所有以上10种状态
    connected : 除了 listening and closed 的剩所有状态(8种状态)
    synchronized :所有 connected 除了 syn-sent (7种状态)
    bucket : 显示状态为maintained as minisockets,如:time-wait和syn-recv.(2种状态)
    big : 和bucket相反.(8种状态)
    

参考链接:
Linux系统使用ss命令查看端口状态

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在网络编程中,当客户端向服务器送请求后,服务器会创建一个套接字用于处理该请求,并在处理完成后关闭该套接字。如果客户端在服务器关闭套接字之前关闭了连接,服务器上的套接字就会进入CLOSE_WAIT状态。这种情况下,如果服务器上存在大量CLOSE_WAIT状态的套接字,就会导致服务器出现性能问题。 要快速释放CLOSE_WAIT状态的套接字,有以下几种方法: 1. 调整TCP的超时参数 可以通过修改TCP的超时参数来加速CLOSE_WAIT状态的套接字释放。具体来说,可以通过调整以下参数: - tcp_fin_timeout:控制FIN包后等待对方回复ACK包的时间,默认为60秒,可以缩短该时间来加速CLOSE_WAIT状态的套接字释放。 - tcp_keepalive_time:控制多长时间后TCP的Keepalive包,用于检测连接是否已经断开,默认为7200秒,可以缩短该时间来加速CLOSE_WAIT状态的套接字释放。 2. 使用SO_REUSEADDR选项 可以在服务器程序中设置SO_REUSEADDR选项,该选项可以让套接字在关闭后立即释放。具体来说,可以在服务器程序中添加以下代码: ``` int reuse = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); ``` 3. 调整系统内核参数 可以通过修改系统内核参数来加速CLOSE_WAIT状态的套接字释放。具体来说,可以调整以下参数: - net.ipv4.tcp_fin_timeout:与tcp_fin_timeout参数含义相同,控制FIN包后等待对方回复ACK包的时间。 - net.ipv4.tcp_keepalive_time:与tcp_keepalive_time参数含义相同,控制多长时间后TCP的Keepalive包。 - net.ipv4.tcp_max_tw_buckets:控制系统最多允许多少个同时处于TIME_WAIT状态的套接字,默认为180000,可以适当增大该值来减少CLOSE_WAIT状态的套接字数量。 以上是一些快速释放CLOSE_WAIT状态的套接字的方法,具体方法应根据实际情况选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值