1. 程式人生 > >time_wait狀態產生的原因,危害,如何避免

time_wait狀態產生的原因,危害,如何避免

1.先來了解TCP四次揮手的過程:

①第一次:主機1(可以使客戶端,也可以是伺服器端),設定Sequence Number和Acknowledgment Number,向主機2傳送一個FIN報文段;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有資料要傳送給主機2了; 

②第二次:主機2收到了主機1傳送的FIN報文段,向主機1回一個ACK報文段,Acknowledgment Number為Sequence Number加1;主機1進入FIN_WAIT_2狀態;主機2告訴主機1,我“同意”你的關閉請求;

③第三次:主機2向主機1傳送FIN報文段,請求關閉連線,同時主機2進入LAST_ACK狀態;

④第四次:主機1收到主機2傳送的FIN報文段,向主機2傳送ACK報文段,然後主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段以後,就關閉連線;此時,主機1等待2MSL後依然沒有收到回覆,則證明Server端已正常關閉,那好,主機1也可以關閉連線了。

注:MSL是指Max Segment Lifetime,即資料包在網路中的最大生存時間。每種TCP協議的實現方法均要指定一個合適的MSL值,如RFC1122給出的建議值為2分鐘,又如Berkeley體系的TCP實現通常選擇30秒作為MSL值。這意味著TIME_WAIT的典型持續時間為1-4分鐘。

2.TCP四次揮手過程中通訊雙方狀態解析:

FIN_WAIT_1: 其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:

FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連線,向對方傳送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。(主動方)

FIN_WAIT_2:實際上FIN_WAIT_2狀態下的SOCKET,表示半連線,也即有一方要求close連線,但另外還告訴對方,我暫時還有點資料需要傳送給你(ACK資訊),稍後再關閉連線。(主動方)

CLOSE_WAIT:表示在等待關閉。當對方close一個SOCKET後傳送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有資料傳送給對方,如果沒有的話,那麼你也就可以 close這個SOCKET,傳送FIN報文給對方,也即關閉連線。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連線。(被動方)

LAST_ACK: 被動關閉一方在傳送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。(被動方)

TIME_WAIT: 表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN WAIT1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。(主動方)

CLOSED: 表示連線中斷。

3.為什麼要有TIME_WAIT這個狀態?

 假設最終的ACK丟失,主機2將重發FIN,主機1必須維護TCP狀態資訊以便可以重發最終的ACK,否則會發送RST,結果主機2認為發生錯誤。TCP實現必須可靠地終止連線的兩個方向(全雙工關閉),主機1必須進入 TIME_WAIT 狀態,因為主機1可能面 臨重發最終ACK的情形。

4.出現太多TIME_WAIT可能導致的後果:

 在高併發短連線的TCP伺服器上,當伺服器處理完請求後立刻按照主動正常關閉連線。這個場景下,會出現大量socket處於TIMEWAIT狀態。如果客戶端的併發量持續很高,此時部分客戶端就會顯示連線不上。
我來解釋下這個場景。主動正常關閉TCP連線,都會出現TIMEWAIT。為什麼我們要關注這個高併發短連線呢?有兩個方面需要注意:

 ① 高併發可以讓伺服器在短時間範圍內同時佔用大量埠,而埠有個0~65535的範圍,並不是很多,刨除系統和其他服務要用的,剩下的就更少了。
 ②在這個場景中,短連線表示“業務處理+傳輸資料的時間 遠遠小於 TIMEWAIT超時的時間”的連線。這裡有個相對長短的概念,比如,取一個web頁面,1秒鐘的http短連線處理完業務,在關閉連線之後,這個業務用過的埠會停留在TIMEWAIT狀態幾分鐘,而這幾分鐘,其他HTTP請求來臨的時候是無法佔用此埠的。單用這個業務計算伺服器的利用率會發現,伺服器幹正經事的時間和埠(資源)被掛著無法被使用的時間的比例是 1:幾百,伺服器資源嚴重浪費。(說個題外話,從這個意義出發來考慮伺服器效能調優的話,長連線業務的服務就不需要考慮TIMEWAIT狀態。同時,假如你對伺服器業務場景非常熟悉,你會發現,在實際業務場景中,一般長連線對應的業務的併發量並不會很高)
     綜合這兩個方面,持續的到達一定量的高併發短連線,會使伺服器因埠資源不足而拒絕為一部分客戶服務。

5.time_wait狀態如何避免

首先伺服器可以設定SO_REUSEADDR套接字選項來通知核心,如果埠忙,但TCP連線位於TIME_WAIT狀態時可以重用埠。在一個非常有用的場景就是,如果你的伺服器程式停止後想立即重啟,而新的套接字依舊希望使用同一埠,此時SO_REUSEADDR選項就可以避免TIME_WAIT狀態。