1. 程式人生 > 實用技巧 >大量TIME_WAIT對線上業務的影響

大量TIME_WAIT對線上業務的影響

文章目錄

TCP的三次握手和四次揮手

TIME_WAIT概述

TIME_WAIT 狀態:

  • TCP 連線中,主動關閉連線的一方出現的狀態;(收到 FIN 命令,進入 TIME_WAIT 狀態,並返回 ACK 命令)

  • 保持 2 個 MSL
    時間,即,4 分鐘 ;(MSL 為 2 分鐘)

TCP 連線建立後,「主動關閉連線」的一端,收到對方的 FIN 請求後,傳送 ACK 響應,會處於 time_wait 狀態;

在高併發的場景下,TIME_WAIT 連線存在,屬於正常現象。

線上場景中,持續的高併發場景

  • 一部分 TIME_WAIT
    連線被回收,但新的 TIME_WAIT
    連線產生;

  • 一些極端情況下,會出現大量TIME_WAIT
    連線。

大量的TIME_WAIT狀態TCP連線,有什麼業務上的影響

  • TCP 連線中,「主動發起關閉連線」的一端,會進入 time_wait 狀態

  • time_wait 狀態,預設會持續 2 MSL


    (報文的最大生存時間),一般是 2x2 mins

  • time_wait 狀態下,TCP 連線佔用的埠,無法被再次使用

  • 每一個 time_wait 狀態,都會佔用一個「本地埠」,上限為 65535
    (16 bit,2 Byte);

  • 當大量的連線處於 time_wait
    時,新建立 TCP 連線會出錯,address already in use : connect 異常

TCP 本地埠數量,上限為 65535 (6.5w),這是因為 TCP 頭部使用 16 bit ,儲存「埠號」,因此約束上限為 65535

現實場景

  • 伺服器端,一般設定:不允許「主動關閉連線」,但 HTTP 請求中,http 頭部 connection 引數,可能設定為 close,則,服務端處理完請求會主動關閉 TCP 連線

    。現在瀏覽器中, HTTP 請求 connection
    引數,一般都設定為 keep-alive

  • Nginx 反向代理場景中,可能出現大量短連結,伺服器端,可能存在

問題分析

大量的TIME_WAIT狀態TCP連線存在,其本質原因是什麼?

  • 大量短連結存在
  • 特別是http請求中,如果connection頭部取值被設定為close時,基本都由【服務端】發起主動關閉連線,而TCP四次揮手關閉連線機制中,為了保證ACK重發和丟棄延遲資料,設定TIME_WAIT為2倍的MSL(報文存活最大時間)

解決TIME_WAIT的辦法

解決上述 time_wait
狀態大量存在,導致新連線建立失敗的問題,一般解決辦法:
1、客戶端,HTTP 請求的頭部,connection 設定為 keep-alive,保持存活一段時間:現在的瀏覽器,一般都這麼進行了
2、伺服器端

  • 允許 time_wait
    狀態的 socket 被重用

  • 縮減 time_wait
    時間,設定為 1 MSL
    (即,2 mins)

幾個核心問題

TIME_WAIT是「伺服器端」的狀態?or 「客戶端」的狀態?

  • RE:time_wait 是「主動關閉 TCP 連線」一方的狀態,可能是「客服端」的,也可能是「伺服器端」的

  • 一般情況下,都是「客戶端」所處的狀態;「伺服器端」一般設定「不主動關閉連線」

務器在對外服務時,是「客戶端」發起的斷開連線?還是「伺服器」發起的斷開連線?

  • 正常情況下,都是「客戶端」發起的斷開連線

  • 「伺服器」一般設定為「不主動關閉連線」,伺服器通常執行「被動關閉」

  • 但 HTTP 請求中,http 頭部 connection 引數,可能設定為 close,則,服務端處理完請求會主動關閉 TCP 連線

關於 HTTP 請求中,設定的主動關閉 TCP 連線的機制:TIME_WAIT的是主動斷開方才會出現的,所以主動斷開方是服務端?

  • 是的。在HTTP1.1協議中,有個 Connection 頭,Connection有兩個值,close和keep-alive,這個頭就相當於客戶端告訴服務端,服務端你執行完成請求之後,是關閉連線還是保持連線,保持連線就意味著在保持連線期間,只能由客戶端主動斷開連線。還有一個keep-alive的頭,設定的值就代表了服務端保持連線保持多久。

  • HTTP預設的Connection值為close,那麼就意味著關閉請求的一方几乎都會是由服務端這邊發起的。那麼這個服務端產生TIME_WAIT過多的情況就很正常了。

  • 雖然HTTP預設Connection值為close,但是,現在的瀏覽器傳送請求的時候一般都會設定Connection為keep-alive了。所以,也有人說,現在沒有必要通過調整引數來使TIME_WAIT降低了。

為什麼需要time_wait

  • 可靠的實現 TCP 全雙工連線的終止:四次揮手關閉 TCP 連線過程中,最後的 ACK 是由「主動關閉連線」的一端發出的,如果這個 ACK 丟失,則,對方會重發 FIN 請求,因此,在「主動關閉連線」的一段,需要維護一個 time_wait 狀態,處理對方重發的 FIN 請求;

  • 處理延遲到達的報文:由於路由器可能抖動,TCP 報文會延遲到達,為了避免「延遲到達的 TCP 報文」被誤認為是「新 TCP 連線」的資料,則,需要在允許新建立 TCP 連線之前,保持一個不可用的狀態,等待所有延遲報文的消失,一般設定為 2 倍的 MSL(報文的最大生存時間),解決「延遲達到的 TCP 報文」問題;