TIME_WAIT linux
客戶端與服務器端創建TCP/IP鏈接後關閉SOCKET後,服務器端鏈接的端口狀態爲TIME_WAIT.主動關閉的一方在發送最後一個 ack 後 nginx
就會進入 TIME_WAIT 狀態 停留2MSL(max segment lifetime)時間 vim
這個是TCP/IP必不可少的,也就是「解決」不了的,也就是TCP/IP設計者原本是這麼設計的 服務器
主要有兩個緣由 cookie
1。防止上一次鏈接中的包,迷路後從新出現,影響新鏈接 app
(通過2MSL,上一次鏈接中全部的重複包都會消失) 異步
2。可靠的關閉TCP鏈接 socket
在主動關閉方發送的最後一個 ack(fin) ,有可能丟失,這時被動方會從新發fin, 若是這時主動方處於 CLOSED 狀態 ,就會響應 rst 而不是 ack。因此主動方要處於 TIME_WAIT 狀態,而不能是 CLOSED 。 tcp
TIME_WAIT 並不會佔用很大資源的,除非受到攻擊。 spa
還有,若是一方 send 或 recv 超時,就會直接進入 CLOSED 狀態
1
netstat -an
查看下,發現系統中有不少time_wait的鏈接。所以直接用一下命令查看詳細狀況
1
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
具體的解決方式
vim /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
// 表示開啓SYN cookies。當出現SYN等待隊列溢出時,啓用cookies來處理,可防範少許SYN攻擊,默認爲0,表示關閉
net.ipv4.tcp_tw_reuse = 1
//表示開啓重用。容許將TIME-WAIT sockets從新用於新的TCP鏈接,默認爲0,表示關閉;
net.ipv4.tcp_tw_recycle = 1
//表示開啓TCP鏈接中TIME-WAIT sockets的快速回收,默認爲0,表示關閉
net.ipv4.tcp_fin_timeout = 30
//修改系統默認的 TIMEOUT 時間
/sbin/sysctl -p //保存後生效
目前看來最好的辦法是讓每一個TIME_WAIT早點過時。
在linux上能夠這麼配置:
#讓TIME_WAIT狀態能夠重用,這樣即便TIME_WAIT佔滿了全部端口,也不會拒絕新的請求形成障礙
echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse
#讓TIME_WAIT儘快回收,我也不知是多久,觀察大概是一秒鐘
echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle
不少文檔都會建議兩個參數都配置上,可是我發現只用修改tcp_tw_recycle就能夠解決問題的了,TIME_WAIT重用TCP協議自己就是不建議打開的。
不能重用端口可能會形成系統的某些服務沒法啓動,好比要重啓一個系統監控的軟件,它用了40000端口,而這個端口在軟件重啓過程當中恰好被使用了,就可能會重啓失敗的。linux默認考慮到了這個問題,有這麼個設定:
#查看系統本地可用端口極限值
cat /proc/sys/net/ipv4/ip_local_port_range
用這條命令會返回兩個數字,默認是:32768 61000,說明這臺機器本地能向外鏈接61000-32768=28232個鏈接,注意是本地向外鏈接,不是這臺機器的全部鏈接,不會影響這臺機器的80端口的對外鏈接數。但這個數字會影響到代理服務器(nginx)對app服務器的最大鏈接數,由於nginx對app是用的異步傳輸,因此這個環節的鏈接速度很快,因此堆積的鏈接就不多。假如nginx對app服務器之間的帶寬出了問題或是app服務器有問題,那麼可能使鏈接堆積起來,這時能夠經過設定nginx的代理超時時間,來使鏈接儘快釋放掉,通常來講極少能用到28232個鏈接。