tcp_tw_recycle和tcp_tw_reuse


tcp TIME_WAIT

進入主題前必須做鋪墊啊,講講TIME_WAIT.因爲TCP連接是雙向的,所以在關閉連接的時候,兩個方向各自都需要關閉。先發FIN包的一方執行的是主動關閉;後發FIN包的一方執行的是被動關閉。主動關閉的一方會進入TIME_WAIT狀態,並且在此狀態停留兩倍的MSL(最大報文存活時間,一般Linux內核設置30秒)時長。

爲什麼主動方要傻乎乎等2MSL呢?不等,行不行?

TCP目的是可靠傳輸,主動關閉的一方發出FIN,被動方回覆ACK,接着被動方發送FIN,主動方收到被動關閉的一方發出的FIN包後,迴應ACK包,同時進入TIME_WAIT狀態,但是因爲網絡原因,主動關閉的一方發送的這個ACK包很可能延遲,從而觸發被動連接一方重傳FIN包。極端情況下,這一去(ACK去被動方)一回(重傳FIN回來),就是兩倍的MSL時長。

如果主動關閉的一方跳過TIME_WAIT直接進入CLOSED,或者在TIME_WAIT停留的時長不足兩倍的MSL,那麼當被動關閉的一方早先發出的FIN延遲包到達或者重傳FIN包到達後,就可能出現類似下面的問題:

  • 主動方舊的TCP連接已經不存在了,主動方只能返回RST
  • 主動方新的TCP連接被建立起來了,延遲包可能干擾新的連接

所以, TIME_WAIT必須等,2MSL不能少

減少TIME_WAIT

TIME_WAIT期間,資源不會釋放,現在都追求高性能高併發,快速釋放資源是躲不掉的.對於客戶端因爲有端口65535問題,TIME_WAIT過多直接影響處理能力. 對於服務器,無端口數量限制的問題,Linux優化也很給力,每個處於TIME_WAIT 狀態下連接內存消耗很少, 而且也能通過tcp_max_tw_buckets = ${你要的閾值} 配置最大上限,但是對於短連接爲主的web服務器,幾十萬的連接,基數很大,耗得內存也不小哦.快速釋放總是好的

  • tcp_tw_recycle:回收TIME_WAIT連接
    對客戶端和服務器同時起作用,開啓後在 3.5*RTO 內回收,RTO 200ms~ 120s 具體時間視網絡狀況。RTO(Retransmission TimeOut)重傳超時時間.內網狀況比tcp_tw_reuse 稍快,公網尤其移動網絡大多要比tcp_tw_reuse 慢,優點就是能夠回收服務端的TIME_WAIT數量

    但是,有個小坑:當多個客戶端通過NAT方式聯網並與服務端交互時,服務端看到的是同一個IP,也就是說對服務端而言這些客戶端實際上等同於一個,可惜由於這些客戶端的時間戳可能存在差異,於是乎從服務端的視角看,便可能出現時間戳錯亂的現象,進而直接導致時間戳小的數據包被丟棄。客戶端處於NAT很常見,基本公司家庭網絡都走NAT.

  • tcp_tw_reuse:複用TIME_WAIT連接 只對客戶端起作用,1秒後才能複用,當創建新連接的時候,如果可能的話會考慮複用相應的TIME_WAIT連接。通常認爲tcp_tw_reusetcp_tw_recycle安全一些,這是因爲一來TIME_WAIT創建時間必須超過一秒纔可能會被複用;二來只有連接的時間戳是遞增的時候纔會被複用。

客戶端請求服務器,服務器響應後主動關閉連接,TIME_WAIT存在於服務器,服務器是被連接者,沒有複用一說,所以只對客戶端起作用.如果是客戶端主動關閉,TIME_WAIT存在於客戶端,這個時候再次連接服務器,可以複用之前TIME_WAIT留下的半廢品.

  • tcp_timestamps:以上兩點,必須在客戶端和服務端timestamps 開啓時才管用(默認開啓) 需要根據timestamp的遞增性來區分是否新連接

總結

  • 客戶端tcp_tw_reuse複用連接管用, tcp_tw_recycle有用,但是客戶端主要不是接受連接,用處不大
  • 服務器tcp_tw_recycle回收連接管用,tcp_tw_reuse複用無效.爲了減少TIME_WAIT留在服務器,可以在服務器開啓KeepAlive,儘量不讓服務器主動關閉,而是客戶端主動關閉,減少TIME_WAIT產生.

More

  • tcp_tw_reuse 和 SO_REUSEADDR 說的完全不是一個東西.

打個例子,舉個比方: 一般來講,在我們寫一個server的時候,會用到SO_REUSEADDR,因爲,當server正在工作的時候,需要重啓,這時候,可能server的一些子進程還在工作,也或者一些連接還處於time_wait狀態,而且time_wait狀態的時間一般比較長,如果沒有SO_REUSEADDR,則會因爲端口被佔用而bind失敗,無法啓動server.

這種模式下典型例子Nginx,一個master進程監聽一個端口,接受連接,將邏輯工作分發給子進程.顯然,單進程監聽分發存在瓶頸,能不能多個進程監聽同一個端口呢?

  • SO_REUSEPORT Linux kernel 3.9帶來了SO_REUSEPORT特性,就是解決上面的問題,讓多個進程同時監聽同一個端口,幹掉單點監聽瓶頸,允許端口重複捆綁
發佈了72 篇原創文章 · 獲贊 54 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章