存在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命令查看端口狀態