天天看點

TCP/IP詳解--TCP連接配接中TIME_WAIT狀态過多

TIMEWAIT狀态本身和應用層的用戶端或者伺服器是沒有關系的。僅僅是主動關閉的一方,在使用FIN|ACK|FIN|ACK四分組正常關閉TCP連接配接的時候會出現這個TIMEWAIT。伺服器在處理用戶端請求的時候,如果你的程式設計為伺服器主動關閉,那麼你才有可能需要關注這個TIMEWAIT狀态過多的問題。如果你的伺服器設計為被動關閉,那麼你首先要關注的是CLOSE_WAIT。

原則

TIMEWAIT并不是多餘的。在TCP協定被創造,經曆了大量的實際場景實踐之後,TIMEWAIT出現了,因為TCP主動關閉連接配接的一方需要TIMEWAIT狀态,它是我們的朋友。這是《UNIX網絡程式設計》的作者----Steven對TIMEWAIT的态度。

TIMEWAIT是友好的

    TCP要保證在所有可能的情況下使得所有的資料都能夠被正确送達。當你關閉一個socket時,主動關閉一端的socket将進入TIME_WAIT狀态,而被動關閉一方則轉入CLOSED狀态,這的确能夠保證所有的資料都被傳輸。當一個socket關閉的時候,是通過兩端四次握手完成的,當一端調用close()時,就說明本端沒有資料要發送了。這好似看來在握手完成以後,socket就都可以處于初始的CLOSED狀态了,其實不然。原因是這樣安排狀态有兩個問題, 首先,我們沒有任何機制保證最後的一個ACK能夠正常傳輸,第二,網絡上仍然有可能有殘餘的資料包(wandering duplicates),我們也必須能夠正常處理。

TIMEWAIT就是為了解決這兩個問題而生的。

1.假設最後一個ACK丢失了,被動關閉一方會重發它的FIN。主動關閉一方必須維持一個有效狀态資訊(TIMEWAIT狀态下維持),以便能夠重發ACK。如果主動關閉的socket不維持這種狀态而進入CLOSED狀态,那麼主動關閉的socket在處于CLOSED狀态時,接收到FIN後将會響應一個RST。被動關閉一方接收到RST後會認為出錯了。如果TCP協定想要正常完成必要的操作而終止雙方的資料流傳輸,就必須完全正确的傳輸四次握手的四個節,不能有任何的丢失。這就是為什麼socket在關閉後,仍然處于TIME_WAIT狀态的第一個原因,因為他要等待以便重發ACK。

2.假設目前連接配接的通信雙方都已經調用了close(),雙方同時進入CLOSED的終結狀态,而沒有走TIME_WAIT狀态。會出現如下問題,現在有一個新的連接配接被建立起來,使用的IP位址與端口與先前的完全相同,後建立的連接配接是原先連接配接的一個完全複用。還假定原先的連接配接中有資料報殘存于網絡之中,這樣新的連接配接收到的資料報中有可能是先前連接配接的資料報。為了防止這一點,TCP不允許新連接配接複用TIME_WAIT狀态下的socket。處于TIME_WAIT狀态的socket在等待兩倍的MSL時間以後(之是以是兩倍的MSL,是由于MSL是一個資料報在網絡中單向發出到認定丢失的時間,一個資料報有可能在發送途中或是其響應過程中成為殘餘資料報,确認一個資料報及其響應的丢棄的需要兩倍的MSL),将會轉變為CLOSED狀态。這就意味着,一個成功建立的連接配接,必然使得先前網絡中殘餘的資料報都丢失了。

大量TIMEWAIT在某些場景中導緻的令人頭疼的業務問題

大量TIMEWAIT出現,并且需要解決的場景

      在高并發短連接配接的TCP伺服器上,當伺服器處理完請求後立刻按照主動正常關閉連接配接。。。這個場景下,會出現大量socket處于TIMEWAIT狀态。如果用戶端的并發量持續很高,此時部分用戶端就會顯示連接配接不上。

我來解釋下這個場景。主動正常關閉TCP連接配接,都會出現TIMEWAIT。為什麼我們要關注這個高并發短連接配接呢?有兩個方面需要注意:

1. 高并發可以讓伺服器在短時間範圍内同時占用大量端口,而端口有個0~65535的範圍,并不是很多,刨除系統和其他服務要用的,剩下的就更少了。

2. 在這個場景中,短連接配接表示“業務處理+傳輸資料的時間 遠遠小于 TIMEWAIT逾時的時間”的連接配接。這裡有個相對長短的概念,比如,取一個web頁面,1秒鐘的http短連接配接處理完業務,在關閉連接配接之後,這個業務用過的端口會停留在TIMEWAIT狀态幾分鐘,而這幾分鐘,其他HTTP請求來臨的時候是無法占用此端口的。單用這個業務計算伺服器的使用率會發現,伺服器幹正經事的時間和端口(資源)被挂着無法被使用的時間的比例是 1:幾百,伺服器資源嚴重浪費。(說個題外話,從這個意義出發來考慮伺服器性能調優的話,長連接配接業務的服務就不需要考慮TIMEWAIT狀态。同時,假如你對伺服器業務場景非常熟悉,你會發現,在實際業務場景中,一般長連接配接對應的業務的并發量并不會很高)

綜合這兩個方面,持續的到達一定量的高并發短連接配接,會使伺服器因端口資源不足而拒絕為一部分客戶服務。同時,這些端口都是伺服器臨時配置設定,無法用SO_REUSEADDR選項解決這個問題:(

一對沖突

TIMEWAIT既友好,又令人頭疼。

但是我們還是要抱着一個友好的态度來看待它,因為它盡它的能力保證了伺服器的健壯性。