c 套接字程式設計中的time_wait close_wait解決
在進行伺服器維護的時候,發現後臺有大量程序處於TIME_WAIT狀態。
如:netstat -antp
而此時客戶端在連線伺服器的時候,出現很卡的現象。重啟伺服器程式(不重啟機器)後,卡頓現象消失,TIME_WAIT狀態的程式消失。在網路上查詢後,得知TIME_WAIT會佔用系統套介面資源,導致客戶端在連線伺服器的時候,套接字不夠用。
那麼什麼是TIME_WAIT狀態?
time_wait狀態是指套接字程式設計中,主動呼叫close關閉連線一方所處的狀態。與TIME_wai類似的還有以下幾種狀態:
TIME_WAIT 主動呼叫close一方的狀態
CLOSE_WAIT 被動關閉一方的狀態,相對於主動呼叫close方。
FIN_WAIT_1 執行close時,己方傳送結束訊號的狀態
FIN_WAIT_2 被動方同意主動方關閉的狀態
一個典型的TCP連線終止可以用圖描述如下:
client server
fin M
close
FIN_WAIT_1 ----------------->close_wait
ack m+1
FIN_WAIT_2 <-----------------read 返回0
fin n
TIME_WAIT <----------------- close
ACK N+1
-----------------> closed
首先客戶端呼叫close(傳送fin m訊號,並處於fin_wait_1狀態),因此客戶端最後會處於TIME_WAIT狀態。
此時伺服器端會接收到資料,此時呼叫read讀取資料,read會返回0.表示對方已經執行了關閉操作。此時伺服器端可以呼叫close,向客戶端傳送fin n訊號。
在程式設計上,客戶端呼叫close以後的所有工作就歸作業系統管理了,此時客戶端的作業系統會向伺服器傳送ack n+1的確認訊號,讓伺服器可以完整的關閉整個連線。這樣整個連線就正常的關閉了。但此時客戶端依然會處於time_wait狀態,因為難免最後的ack n+1訊號會丟失,需要重發。
以上講述了客戶端先呼叫close的情形,在實際情況下,伺服器端也會由於客戶端崩潰或其他機制主動執行close。此時伺服器端也會存在一些程序處於TIME_WAIT狀態。伺服器上如果TIME_WAIT程序較多,就會影響伺服器的效能。因為套接字也是一種系統資源,這種資源總是有限的。此時就需要調整系統引數來降低time_wait的程序數(如果是錯誤的程式設計的話,請先修改程式碼錯誤)。
方法vim /etc/sysctl.conf
#對於一個新建連線,核心要傳送多少個 SYN 連線請求才決定放棄,不應該大於255,預設值是5,對應於180秒左右時間
net.ipv4.tcp_syn_retries=2
#net.ipv4.tcp_synack_retries=2
#表示當keepalive起用的時候,TCP傳送keepalive訊息的頻度。預設是2小時,改為300秒
net.ipv4.tcp_keepalive_time=1200
net.ipv4.tcp_orphan_retries=3
#表示如果套接字由本端要求關閉,這個引數決定了它保持在FIN-WAIT-2狀態的時間
net.ipv4.tcp_fin_timeout=30
#表示SYN佇列的長度,預設為1024,加大佇列長度為8192,可以容納更多等待連線的網路連線數。
net.ipv4.tcp_max_syn_backlog = 4096
#表示開啟SYN Cookies。當出現SYN等待佇列溢位時,啟用cookies來處理,可防範少量SYN攻擊,預設為0,表示關閉
net.ipv4.tcp_syncookies = 1
#表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連線,預設為0,表示關閉
net.ipv4.tcp_tw_reuse = 1
#表示開啟TCP連線中TIME-WAIT sockets的快速回收,預設為0,表示關閉
net.ipv4.tcp_tw_recycle = 1
##減少超時前的探測次數
net.ipv4.tcp_keepalive_probes=5
##優化網路裝置接收佇列
net.core.netdev_max_backlog=3000
修改後使用/sbin/sysctl -p讓引數生效。
如果伺服器存在大量的close_wait。則表示程式碼沒有呼叫close來被動關閉連線。請檢查程式碼是否有對這種情況進行處理。。