-
當前位置:首頁 > 創(chuàng)意學院 > 技術 > 專題列表 > 正文
出現大量time_wait狀態(tài)(大量timewait狀態(tài)的后果)
大家好!今天讓創(chuàng)意嶺的小編來大家介紹下關于出現大量time_wait狀態(tài)的問題,以下是小編對此問題的歸納整理,讓我們一起來看看吧。
ChatGPT國內免費在線使用,一鍵生成原創(chuàng)文章、方案、文案、工作計劃、工作報告、論文、代碼、作文、做題和對話答疑等等
只需要輸入關鍵詞,就能返回你想要的內容,越精準,寫出的就越詳細,有微信小程序端、在線網頁版、PC客戶端
本文目錄:
一、netstat查詢到本機的有大量127.0.0.1各種不同端口處于TIME_WAIT狀態(tài),是什么原因?
電腦網絡問題。根據你的描述,netstat查詢到本機的有大量127.0.0.1各種不同端口處于TIME_WAIT狀態(tài),是因為:
1,有程序或者病毒預留了這些端口。
2,系統(tǒng)沒有優(yōu)化,開啟了過多無用端口。
二、開始運行CMD 里打 netstat -an 出現一堆TIME_WAIT 怎么回事
1:連接協議 udp tcp
2:對應的本地地址及連接端口
3:對應的遠程地址及端口
4:連接狀態(tài)
LISTENING 監(jiān)聽
TIME_WAIT 超時
ESTABLISHED 正在通信
三、【TCP】 tcp四次揮手狀態(tài) TIME_WAIT
首先,我們需要明確, 只有主動斷開的那一方才會進入 TIME_WAIT 狀態(tài) ,且會在那個狀態(tài)持續(xù) 2 個 MSL(Max Segment Lifetime)。
為了講清楚 TIME_WAIT,需要先介紹一下 MSL 的概念。
MSL(報文最大生存時間)是 TCP 報文在網絡中的最大生存時間。這個值與 IP 報文頭的 TTL 字段有密切的關系。
IP 報文頭中有一個 8 位的存活時間字段(Time to live, TTL)如下圖。 這個存活時間存儲的不是具體的時間,而是一個 IP 報文最大可經過的路由數,每經過一個路由器,TTL 減 1,當 TTL 減到 0 時這個 IP 報文會被丟棄。
TTL 經過路由器不斷減小的過程如下圖所示,假設初始的 TTL 為 12,經過下一個路由器 R1 以后 TTL 變?yōu)?11,后面每經過一個路由器以后 TTL 減 1
從上面可以看到 TTL 說的是「跳數」限制而不是「時間」限制,盡管如此我們依然假設 最大跳數的報文在網絡中存活的時間不可能超過 MSL 秒 。
Linux 的套接字實現假設 MSL 為 30 秒,因此在 Linux 機器上 TIME_WAIT 狀態(tài)將持續(xù) 60秒。
要構造一個 TIME_WAIT 非常簡單,只需要建立一個 TCP 連接,然后斷開某一方連接,主動斷開的那一方就會進入 TIME_WAIT 狀態(tài),我們用 Linux 上開箱即用的 nc 命令來構造一個。
過程如下圖:
在機器 c2 上用nc -l 8888啟動一個 TCP 服務器
在機器 c1 上用 nc c2 8888 創(chuàng)建一條 TCP 連接
在機器 c1 上用 Ctrl+C 停止 nc 命令,隨后在用netstat -atnp | grep 8888查看連接狀態(tài)。
第一個原因是:數據報文可能在發(fā)送途中延遲但最終會到達,因此要等老的“迷路”的重復報文段在網絡中過期失效,這樣可以避免用相同源端口和目標端口創(chuàng)建新連接時收到舊連接姍姍來遲的數據包,造成數據錯亂。
比如下面的例子
假設客戶端 10.211.55.2 的 61594 端口與服務端 10.211.55.10 的 8080 端口一開始建立了一個 TCP 連接。
假如客戶端發(fā)送完 FIN 包以后不等待直接進入 CLOSED 狀態(tài),老連接 SEQ=3 的包因為網絡的延遲。過了一段時間 相同 的 IP 和端口號又新建了另一條連接,這樣 TCP 連接的四元組就完全一樣了。
恰好 SEQ 因為回繞等原因 也正好相同,那么 SEQ=3 的包就無法知道到底是舊連接的包還是新連接的包了,造成新連接數據的混亂。
TIME_WAIT 等待時間是 2 個 MSL,已經足夠讓一個方向上的包最多存活 MSL 秒就被丟棄,保證了在創(chuàng)建新的 TCP 連接以后,老連接姍姍來遲的包已經在網絡中被丟棄消逝,不會干擾新的連接。
第二個原因是確??煽繉崿F TCP 全雙工終止連接。
關閉連接的四次揮手中,最終的 ACK 由主動關閉方發(fā)出,如果這個 ACK 丟失,對端(被動關閉方)將重發(fā) FIN,如果主動關閉方不維持 TIME_WAIT 直接進入 CLOSED 狀態(tài),則無法重傳 ACK,被動關閉方因此不能及時可靠釋放。
如果四次揮手的第 4 步中客戶端發(fā)送了給服務端的確認 ACK 報文以后不進入 TIME_WAIT 狀態(tài),直接進入 CLOSED狀態(tài),然后重用端口建立新連接會發(fā)生什么呢?
如下圖所示
主動關閉方如果馬上進入 CLOSED 狀態(tài),被動關閉方這個時候還處于LAST-ACK狀態(tài),主動關閉方認為連接已經釋放,端口可以重用了, 如果使用相同的端口三次握手發(fā)送 SYN 包,會被處于 LAST-ACK狀態(tài)狀態(tài)的被動關閉方返回一個 RST,三次握手失敗。
為什么時間是兩個 MSL?
1 個 MSL 確保四次揮手中主動關閉方最后的 ACK 報文最終能達到對端
1 個 MSL 確保對端沒有收到 ACK 重傳的 FIN 報文可以到達
2MS = 去向 ACK 消息最大存活時間(MSL) + 來向 FIN 消息的最大存活時間(MSL)
在一個非常繁忙的服務器上,如果有大量 TIME_WAIT 狀態(tài)的連接會怎么樣呢?
連接表無法復用
socket 結構體內存占用
連接表無法復用 因為處于 TIME_WAIT 的連接會存活 2MSL(60s),意味著相同的TCP 連接四元組(源端口、源 ip、目標端口、目標 ip)在一分鐘之內都沒有辦法復用,通俗一點來講就是“占著茅坑不拉屎”。
假設主動斷開的一方是客戶端,對于 web 服務器而言,目標地址、目標端口都是固定值(比如本機 ip + 80 端口),客戶端的 IP 也是固定的,那么能變化的就只有端口了,在一臺 Linux 機器上,端口最多是 65535 個( 2 個字節(jié))。
如果客戶端與服務器通信全部使用短連接,不停的創(chuàng)建連接,接著關閉連接,客戶端機器會造成大量的 TCP 連接進入 TIME_WAIT 狀態(tài)。
可以來寫一個簡單的 shell 腳本來測試一下,使用 nc 命令連接 redis 發(fā)送 ping 命令以后斷開連接。
如果在 60s 內有超過 65535 次 redis 短連接操作,就會出現端口不夠用的情況,這也是使用 連接池 的一個重要原因。
針對 TIME_WAIT 持續(xù)時間過長的問題,Linux 新增了幾個相關的選項,net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_tw_recycle。
下面我們來說明一下這兩個參數的用意。 這兩個參數都依賴于 TCP 頭部的擴展選項:timestamp
TCP 頭部時間戳選項(TCP Timestamps Option,TSopt)
除了我們之前介紹的 MSS、Window Scale 還有以一個非常重要的選項:時間戳(TCP Timestamps Option,TSopt)
它由四部分構成:類別(kind)、長度(Length)、發(fā)送方時間戳(TS value)、回顯時間戳(TS Echo Reply)。
時間戳選項類別(kind)的值等于 8,用來與其它類型的選項區(qū)分。長度(length)等于 10。兩個時間戳相關的選項都是 4 字節(jié)。
如下圖所示:
是否使用時間戳選項是在三次握手里面的 SYN 報文里面確定的。
下面的包是 curl github.com 抓包得到的結果:
發(fā)送方發(fā)送數據時,將一個發(fā)送時間戳 1734581141 放在發(fā)送方時間戳 TSval 中
接收方收到數據包以后,將收到的時間戳 1734581141 原封不動的返回給發(fā)送方,放在 TSecr 字段中,同時把自己的時間戳 3303928779 放在 TSval 中
后面的包以此類推
有幾個需要說明的點:
1. 時間戳是一個單調遞增的值,與我們所知的 epoch 時間戳不是一回事。 這個選項不要求兩臺主機進行時鐘同步
2. timestamps 是一個雙向的選項,如果只要有一方不開啟,雙方都將停用 timestamps。
比如下面是curl www.baidu.com得到的包
可以看到客戶端發(fā)起 SYN 包時帶上了自己的TSval,服務器回復的SYN+ACK 包沒有TSval和TSecr,從此之后的包都沒有帶上時間戳選項了。
有了這個選項,我們來看一下 tcp_tw_reuse 選項。
緩解緊張的端口資源,一個可行的方法是重用“浪費”的處于 TIME_WAIT 狀態(tài)的連接,當開啟 net.ipv4.tcp_tw_reuse 選項時,處于 TIME_WAIT 狀態(tài)的連接可以被重用。
下面把主動關閉方記為 A, 被動關閉方記為 B,它的原理是:
如果主動關閉方 A 收到的包時間戳比當前存儲的時間戳小,說明是一個迷路的舊連接的包,直接丟棄掉
如果因為 ACK 包丟失導致被動關閉方還處于LAST-ACK狀態(tài),并且會持續(xù)重傳 FIN+ACK。這時 A 發(fā)送SYN 包想三次握手建立連接,此時 A 處于SYN-SENT階段。 當收到 B 的 FIN 包時會回以一個 RST 包給 B,B 這端的連接會進入 CLOSED 狀態(tài),A 因為沒有收到 SYN 包的 ACK,會重傳 SYN,后面就一切順利了。
tcp_tw_recyle 是一個比 tcp_tw_reuse 更激進的方案, 系統(tǒng)會緩存每臺主機(即 IP)連接過來的最新的時間戳。
對于新來的連接,如果發(fā)現 SYN 包中帶的時間戳與之前記錄的來自同一主機的同一連接的分組所攜帶的時間戳相比更舊,則直接丟棄;如果更新則接受復用 TIME-WAIT 連接。
這種機制在客戶端與服務端一對一的情況下沒有問題,如果經過了 NAT 或者負載均衡,問題就很嚴重了。
什么是 NAT呢?
NAT(Network Address Translator)的出現是為了緩解 IP 地址耗盡的臨時方案,IPv4 的地址是 32 位,全部利用最 多只能提 42.9 億個地址,去掉保留地址、組播地址等剩下的只有 30 多億,互聯網主機數量呈指數級的增長,如果給每個設備都分配一個唯一的 IP 地址,那根本不夠。于是 1994 年推出的 NAT 規(guī)范,NAT 設備負責維護局域網私有 IP 地址和端口到外網 IP 和端口的映射規(guī)則。
它有兩個明顯的優(yōu)點:
出口 IP 共享:通過一個公網地址可以讓許多機器連上網絡,解決 IP 地址不夠用的問題
安全隱私防護:實際的機器可以隱藏自己真實的 IP 地址 當然也有明顯的弊端:NAT 會對包進行修改,有些協議無法通過 NAT。
當 tcp_tw_recycle 遇上 NAT 時,因為客戶端出口 IP 都一樣,會導致服務端看起來都在跟同一個 host 打交道。
不同客戶端攜帶的 timestamp 只跟自己相關,如果一個時間戳較大的客戶端 A 通過 NAT 與服務器建連,時間戳較小的客戶端 B 通過 NAT 發(fā)送的包服務器認為是過期重復的數據,直接丟棄,導致 B 無法正常建連和發(fā)數據。
TIME_WAIT 狀態(tài)是最容易造成混淆的一個概念,這個狀態(tài)存在的意義是:
1. 可靠的實現 TCP 全雙工的連接終止(處理最后 ACK 丟失的情況)
2. 避免當前關閉連接與后續(xù)連接混淆(讓舊連接的包在網絡中消逝)
假設 MSL 是 60s,請問系統(tǒng)能夠初始化一個新連接然后主動關閉的最大速率是多少(忽略1~1024區(qū)間的端口)?
2MSL = 120s,(65535 - 1024) / 120 = 537.6 次/秒
每120秒可以初始化(65535-1024 )個
“時間戳是一個單調遞增的值,與我們所知的 epoch 時間戳不是一回事” 這個epoch和時間戳分別是什么差異?
不是一回事,跟時間沒有什么關系,只是隨著時鐘信號CPU中斷遞增。
SO_REUSEADDR是針對服務端的,tcp_tw_reuse和tcp_tw_recyle是針對客戶端的,可以這樣理解嗎?
SO_REUSEADDR 兩端都可以用,不過服務端上因為經常要固定端口,不設置,下次重啟就bind 失敗 。
tcp_tw_reuse和tcp_tw_recyle 也是主要用于繁忙的“服務端”,“客戶端”和“服務端”這個說法是在不同的場景下可以互相轉換的,服務端也可以發(fā)起請求充當客戶端 。
深入理解 TCP 協議:從原理到實戰(zhàn)
https://juejin.cn/book/6844733788681928712/section/6844733788837117959
從SO_REUSEADDR選項說起
https://zhuanlan.zhihu.com/p/31329253
四、Linux下netstat查看處于TIME_WAIT的socket過多
在Linux中使用如下的命令查看Linux內核中各種狀態(tài)的socket
在答主電腦中如下所示:
各個狀態(tài)的socket:
CLOSED:無連接是活動的或正在進行
LISTEN:服務器在等待進入呼叫
SYN_RECV:一個連接請求已經到達,等待確認
SYN_SENT:應用已經開始,打開一個連接
ESTABLISHED:正常數據傳輸狀態(tài)
FIN_WAIT1:應用說它已經完成
FIN_WAIT2:另一邊已同意釋放
ITMED_WAIT:等待所有分組死掉
CLOSING:兩邊同時嘗試關閉
TIME_WAIT:另一邊已初始化一個釋放
LAST_ACK:等待所有分組死掉
如果目前內核中存在大量處于TIME_WAIT狀態(tài)的socket,那么說明這些socket還沒有被釋放掉,它們還占用著資源,這樣就有可能導致操作系統(tǒng)的負載過高,怎么解決這個問題呢?
通過調整內核參數來解決:
增加如下內容:
執(zhí)行下面命令讓參數生效:
以上就是關于出現大量time_wait狀態(tài)相關問題的回答。希望能幫到你,如有更多相關問題,您也可以聯系我們的客服進行咨詢,客服也會為您講解更多精彩的知識和內容。
推薦閱讀: