1. 程式人生 > 其它 >Linux下TIME_WAIT狀態TCP連線優化引數tcp_tw_reuse與tcp_tw_recycle區別與聯絡淺析

Linux下TIME_WAIT狀態TCP連線優化引數tcp_tw_reuse與tcp_tw_recycle區別與聯絡淺析

概述

最近學習網路相關知識點,很多文章提到針對TCP time wait(後續簡稱TW)狀態連線進行優化的引數tcp_tw_reuse和tcp_tw_recycle,並且不少文章提到了啟用tcp_tw_recycle會導致的問題,不建議開啟該選項,但是並沒有找到一篇能完全解答自己所有疑惑的文章,如:

  1. Linux會丟棄所有來自遠端的timestramp時間戳小於上次記錄的時間戳(由同一個遠端傳送的)的任何資料包。也就是說要使用該選項,則必須保證資料包的時間戳是單調遞增的,這裡的遠端定義的是ip還是ip+port? 是一定時間內丟棄時間戳過期packet還是tcp_tw_recycle啟用後一直丟棄?
  2. 很多文章都會提到tcp_tw_reuse 僅作用於客戶端連線,tcp_tw_recycle則同時作用於客戶端與服務端連線,這裡客戶端、服務端連線具體指的是什麼?與TCP三次握手的客戶端、服務端概念上有什麼區別?

通過學習網上大家的總結+閱讀了部分4.9核心原始碼,這裡整理總結一下從各處學習到的知識點及自己的理解。

過多time wait會導致的問題

  1. 客戶端主動發起的連線總數受 max open file數限制,過多連線導致達到max open file限制將無法建立新的連線。
  2. 客戶端主動發起的連線總數也受可用埠號限制,一般使用埠號為1024~65000,如果過多TW連線將埠號耗盡同樣無法再建立新的連線。
  3. 每個TW連線都會佔用一定的系統資源-如記憶體--實際耗費記憶體很小,這點一般可忽略

tcp_tw_reuse與tcp_tw_recycle相同點

  1. 兩者目的均是為了解決系統中過多TW狀態 TCP連線的問題。
  2. 兩者都需要和tcp_timestamps 同時開啟方能生效。
  3. 根據RFC定義,主動關閉連線方其TW狀態需維持2MSL時間才正式關閉連線,Linux上MSL預設定義為30s,即TW狀態預設需要維持1分鐘方能正式關閉,tcp_tw_reuse與tcp_tw_recycle均為通過縮短TW狀態時間進行復用來進行優化。
  4. 兩個引數預設均為關閉狀態

tcp_tw_reuse原理

  1. 僅作用於客戶端方主動發起連線,即出向連線。
  2. 連線進入TW狀態>1s,且新連線的timestamp大於舊連線記錄的timestamp時方能複用連線。
  3. client提前中止TW狀態進行復用,發起新連線,server依然處於last ack狀態時,互動流程如下:
    1. client傳送新SYN => server
    2. client <= server由於處於LAST ACK,不理會SYN,重發 FIN+ACK
    3. client收到FIN+ACK,發現timestamp已過期,傳送RST => server, server收到後重置關閉舊連線
    4. client初始傳送的SYN包等待ACK超時1s後,重發SYN => server
    5. client <= server 會發 SYN+ACK 進入正常三次握手連線過程...
    6. 新連線建立完成後,client/server若收到舊連線的歷史報文,通過timestamp可判斷出為舊報文直接丟棄
      整個過程中可以看到,client端可以正常複用發起新的連線,在server端依然處於LAST ACK狀態時也只是需要稍微延遲一小段時間而已。

tcp_tw_recycle原理

  1. 同時作用於client/server發起連線,即出、入向連線
  2. TW狀態維持3.5RTO(the retransmission timeout (RTO) interval which is computed from the RTT and its variance)之後就直接可以被過期回收,具體RTO取值是基於網路RTT及其他相關因子綜合計算。
  3. TW狀態後2MSL會丟棄所有來自遠端相同四元組的timestamp小於上次記錄timestamp的任何資料包,因而需要保證資料包timestamp是單調遞增的
    1. NAT情況下,不同client從同一NAT ip請求,由於NAT不會更改包中的timestamp,而不同機器的時間不可能完全同步,因而不同機器從同一個NAT IP+port發出的包會存在timestamp非單調遞增的情況,問題場景舉例:
      1. 機器A時間比機器B快1s,機器A先通過NAT機器 ip1:port1 對伺服器S ip2: port2 發起tcp連線socket1--使用conn_old(ip1, port1, ip2, port2)四元組表示
      2. 後S主動斷開連線進入TW狀態,由於開啟tcp_tw_recycle,經過一個RTO後S即可複用conn_old這個連線
      3. NAT機器對應連線在進入LAST ACK並收到S回覆的ACK之後關閉了conn_old
      4. 而後機器B通過NAT機器發起conn_new(ip1, port1, ip2, port2)
      5. 此時S收到SYN包發現timestamp 小於conn_old中記錄的最終timestamp,於是丟棄conn_new的SYN包
      6. 機器B超時未收到回覆,重發SYN包,機器S收到後比較timestamp後繼續丟棄....如此往復,最終導致通過NAT機器發起的conn_new(ip1, port1, ip2, port2)在TW狀態終止的2MSl內都無法建立新的連線,對於機器B的使用者表現就是連線遲遲無法建立成功。
    2. 高版本核心由於新的時間戳生成演算法tcp: randomize tcp timestamp offsets for each connection 即便未使用NAT也會導致同一臺機器不同socket之間timestamp非單調遞增
  4. Linux從4.12版本核心開始已經移除了tcp_tw_recycle支援

文章開始時兩個問題的答案

  1. 遠端定義為ip+port,無論tcp_tw_reuse還是tcp_tw_recycle,針對回收TW連線對新連線的影響,都是指同一四元組代表的連線(src_ip, src_port, dst_ip, dst_port),任何時候收到過期timestamp包都會直接丟棄,而不止是TW的2MSL時間內
  2. 客戶端是指主動發起連線的一方,即TCP三次握手中發出首個SYN包的一方。

轉載請註明出處,原文地址:https://www.cnblogs.com/AcAc-t/p/tcp_tw_reuse_and_tcp_tw_recycle_introduction.html

參考:

簽名:擁抱開源,擁抱自由