TCP連線中TIME WAIT連線過多

2021-07-04 01:13:30 字數 3171 閱讀 1301

原文

主題tcp/ip

socket

timewait並不是多餘的 。 在tcp協議被創造, 經歷了大量的實際場景實踐之後 ,timewait 出現了,因為tcp主 動關閉連線的一方需要timewait狀態,它是我們的朋友。這是 《 

unix網路程式設計 》的作者----steven對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出現,並且需要解決 的場景 

在高並發短連線的tcp伺服器上,當伺服器處理完 請求後立刻按照主動正常 關閉連線。。。這個場景下, 會出現大量socket處於 timewai t 狀態。如果客戶端的併發量持續很高, 此時部分客戶端就會顯示 連線不上。 

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

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

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

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

timewait既友好,又令人頭疼。 

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

1. linux沒有在sysctl或者proc檔案系統暴露修改 這個timewait超時時間的介面 ,可以修改核心協議棧**中關於這個timewait的超時時間引數,重編核心,讓它縮短超時時間,加快**; 

2. 利用so_linger選項的強制關閉方式,發rst而不是fin,來越過timewait狀態,直接進入closed狀態。詳見我的博 文 

《tcp之選項

so_linger

》 。 

為什麼說上述兩種解決方式我覺得可行,但是不符合原則? 

我首先認為,我要依靠timewait狀態來保證我的伺服器程式健壯,網路上發生的亂七八糟的問題太多了,我先要服務功能正常。 

那是不是就不要效能了呢?並不是。如果伺服器上跑的短連線業務量到了我真的必須處理這個timewait狀態過多的問題的時候,我的原則是盡量處理,而不是跟timewait幹上,非先除之而後快:)如果 

真正地必須使用 上述我認為不合理的方式 來解決這個問題的場景有沒有呢?答案是有。 

題外話,伺服器上的技術問題沒有絕對,一切都是為業務需求服務的。 

sysctl改兩個核心引數就行了,如下: 

net.ipv4.tcp_tw_reuse = 1 

net.ipv4.tcp_tw_recycle = 1 

簡單來說,就是開啟系統的timewait重用和快速**,至於怎麼重用和快速**,這個問題 我沒有深究,實際場景中這麼做確實有效果。 用netstat或者ss觀察就能得出結論。 

還有些朋友同時也會開啟syncookies這個功能,如下: 

net.ipv4.tcp_syncookies = 1 

開啟這個syncookies 的 目的實際上是: 「在伺服器資源(並非單指埠資源,拒絕服務有很多種資源不足的情況 )不足的 情況下,盡量不要拒絕tcp的 syn(連線 )請求,盡量把syn請求快取起來,留著過會兒有能力的時候 處理這些tcp的連線請求 」。 

如果併發量真的非常非常高,開啟這個其實用處不大。

TCP連線中的TIME WAIT狀態

根據 unix網路程式設計 卷1,tcp的狀態轉換圖可以得知 執行主動關閉的那端 假設客戶端 經歷了time wait狀態,該狀態停留在那個狀態的持續時間是最長分節期 maximum segment lifetime,msl 的兩倍,稱為2msl。time wait狀態的持續時間在1min 4min...

tcp連線中TIME WAIT狀態過多

參考自 作用 1.保證雙方正常種植資料流傳輸 最後乙個 ack丟失了,被動關閉一方會重發它的 fin,主動關閉一方必須維持乙個有效狀態資訊 timewait狀態下維持 以便能夠重發 ack,否則被動一方會認為有錯誤產生 2.保證 在下乙個人使用的ip位址與埠與先前的完全相同的情況下,上乙個殘留的資料...

TCP連線的TIME WAIT狀態

time wait狀態是tcp的11個狀態其中之一,是發生在正常關閉tcp連線的時候發生的。如下圖所示 在這幅圖中我們可以明顯看出,流程是這樣的,顯示主動傳送乙個fin報文,然後接收到乙個ack報文,這樣這一方的連線已經關閉,也就是不能再傳送資料了,進入fin wait2狀態,這個狀態就是為了等待,...