上一篇文章提到執行主動關閉的一端進入 tcp TIME_WAIT狀態,關于原因,unix網絡編程卷一中給出兩點:
1. 實現終止TCP全雙工鏈接的可靠性,即保證tcp連接可靠斷開。
2. 讓老的重復分節在網絡中消失
第一個原因的解釋,執行主動關閉的一端最終會發ACK給對端,如果這個ACK最終丟失,那么發FIN的對端將由于在等待ACK超時后重發FIN分節,而如果主動關閉的一端在發完最終的ACK后清除此連接上狀態信息,當再次收到對端的FIN分節時由于找不到對應的連接而報錯,所以,如果TCP想徹底終止某個連接上兩個方向的數據流(即全雙工關閉),那么它必須處理連接終止序列四個分節中任何一個分節丟失的情況,這就是為何執行主動關閉的一端進入TIME_WAIT狀態的第一個原因,因為它可能不得不重發最終的ACK分節給對端。
第二個原因,假設在一對ip及port上有一個連接,關閉這個連接后立即又建立起新的連接(同ip port),后一個連接為前一個的化身,因為ip port相同,tcp 必須防止來自某個連接的老分組在連接終止后再現,從而影響新連接的數據交互,所以tcp不能給處于TIME_WAIT狀態的連接啟動新的化身,從而被誤解成屬于同一連接。
TIME_WAIT狀態的持續時間是最長分節生命期MSL(max segment lifetime)的2倍,即2MSL,既然tcp規定一個分節在網絡中最大生存時間是 MSL,這足夠讓某個方向上的分節最多存活MSL秒即被丟棄,另一個方向的應答最多存活MSL秒也被丟棄,通過這個規則,就能保證當成功建立一個tcp連接時,來自該鏈接的之前所有連接的老的重復分組在網絡中已消失。
每個TCP/IP 協議棧必須選擇一個 MSL值,rfc 1122建議值為2分鐘,而源自berkely的實現是30秒,需要注意的是如果此值過大,則在高并發服務器中tcp/ip協議棧必然要維護大量的TIME_WAIT狀態的連接而消耗資源,所以一般作網絡服務器優化時通常經過改小此值來減少維護此狀態的資源。
詳細設置及解決如下:
timeout_timewait 參數
描述:確定 TCP/IP 在釋放已關閉的連接并再次使用其資源前必須經過的時間。關閉與釋放之間的這段時間稱為 TIME_WAIT 狀態或者兩倍最大段生存期(2MSL)狀態。此時間期間,重新打開到客戶機和服務器的連接的成本少于建立新連接。通過減少此條目的值,TCP/IP 可以更快地釋放關閉的連接,并為新連接提供更多資源。如果正在運行的應用程序需要快速釋放連接、創建新的連接,并且因為許多連接處于 TIME_WAIT 狀態而導致低吞吐量,那么調整此參數。
如何查看或設置:
在我的ubuntu系統上此值為:
#cat ?/proc/sys/net/ipv4/tcp_fin_timeout?
60
發出以下命令,將 timeout_timewait 參數設置為 30 秒:
#echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout