大量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 連線
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 報文」問題;