存在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会比较多
解决方法:可以通过修改系统配置和客户端程序解决
说明:
-
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选项快速回收)
-
调整客户端程序,采取一些限频措施(可以使用连接池,缓存等技术,以减少客户端发起的请求数)
处理这类问题的实用命令
-
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命令查看端口状态