网络:TIME-WAIT
time_wait狀態(tài)產(chǎn)生的原因,危害,如何避免
0.請說說你對TCP連接中time_wait狀態(tài)的理解?
解答:
先上TCP的狀態(tài)變遷圖
上面這個圖片展示了TCP從連接建立到連接釋放的過程中,客戶端和服務(wù)端的狀態(tài)變化圖。如果只看連接釋放階段,四次握手
·????????客戶端先發(fā)送FIN,進入FIN_WAIT1狀態(tài)
·????????服務(wù)端收到FIN,發(fā)送ACK,進入CLOSE_WAIT狀態(tài),客戶端收到這個ACK,進入FIN_WAIT2狀態(tài)
·????????服務(wù)端發(fā)送FIN,進入LAST_ACK狀態(tài)
·????????客戶端收到FIN,發(fā)送ACK,進入TIME_WAIT狀態(tài),服務(wù)端收到ACK,進入CLOSE狀態(tài)
·????????客戶端TIME_WAIT持續(xù)2倍MSL時長,在linux體系中大概是60s,轉(zhuǎn)換成CLOSE狀態(tài)
當(dāng)然在這個例子和上面的圖片中,使用客戶端和服務(wù)端來描述是不準(zhǔn)確的,TCP主動斷開連接的一方可能是客戶端,也可能是服務(wù)端。所以使用主動斷開的一方,和被動斷開的一方替換上面的圖可能更為貼切。
不管怎么說,TIME_WAIT的狀態(tài)就是主動斷開的一方,發(fā)送完最后一次ACK之后進入的狀態(tài)。并且持續(xù)時間還挺長的。
0.能不能發(fā)送完ACK之后不進入TIME_WAIT就直接進入CLOSE狀態(tài)呢?
不行的,這個是為了TCP協(xié)議的可靠性,由于網(wǎng)絡(luò)原因,ACK可能會發(fā)送失敗,那么這個時候,被動一方會主動重新發(fā)送一次FIN,這個時候如果主動方在TIME_WAIT狀態(tài),則還會再發(fā)送一次ACK,從而保證可靠性。那么從這個解釋來說,2MSL的時長設(shè)定是可以理解的,MSL是報文最大生存時間,如果重新發(fā)送,一個FIN+一個ACK,再加上不定期的延遲時間,大致是在2MSL的范圍。
所以從理論上說,網(wǎng)上調(diào)試參數(shù)降低TIME_WAIT的持續(xù)時間的方法是一種以可靠性換取性能的一種方式。嗯,質(zhì)量守恒定理還是鐵律。
?
1. time_wait狀態(tài)如何產(chǎn)生??
由上面的變遷圖,首先調(diào)用close()發(fā)起主動關(guān)閉的一方,在發(fā)送最后一個ACK之后會進入time_wait的狀態(tài),也就說該發(fā)送方會保持2MSL時間之后才會回到初始狀態(tài)。MSL的值是數(shù)據(jù)包在網(wǎng)絡(luò)中的最大生存時間。產(chǎn)生這種結(jié)果使得這個TCP連接在2MSL連接等待期間,定義這個連接的四元組(客戶端IP地址和端口,服務(wù)端IP地址和端口號)不能被使用。(IP:PORT already inuse)
2.time_wait狀態(tài)產(chǎn)生的原因?
1)為實現(xiàn)TCP全雙工連接的可靠釋放
由TCP狀態(tài)變遷圖可知,假設(shè)發(fā)起主動關(guān)閉的一方(client)最后發(fā)送的ACK在網(wǎng)絡(luò)中丟失,由于TCP協(xié)議的重傳機制,執(zhí)行被動關(guān)閉的一方(server)將會重發(fā)其FIN,在該FIN到達client之前,client必須維護這條連接狀態(tài),也就說這條TCP連接所對應(yīng)的資源(client方的local_ip,local_port)不能被立即釋放或重新分配,直到另一方重發(fā)的FIN達到之后,client重發(fā)ACK后,經(jīng)過2MSL時間周期沒有再收到另一方的FIN之后,該TCP連接才能恢復(fù)初始的CLOSED狀態(tài)。
如果主動關(guān)閉一方不維護這樣一個TIME_WAIT狀態(tài),那么當(dāng)被動關(guān)閉一方重發(fā)的FIN到達時,主動關(guān)閉一方的TCP傳輸層會用RST包響應(yīng)對方,這會被對方認(rèn)為是有錯誤發(fā)生,然而這事實上只是正常的關(guān)閉連接過程,并非異常。
2)為使舊的數(shù)據(jù)包在網(wǎng)絡(luò)因過期而消失
為說明這個問題,我們先假設(shè)TCP協(xié)議中不存在TIME_WAIT狀態(tài)的限制,再假設(shè)當(dāng)前有一條TCP連接:(local_ip, local_port,remote_ip,remote_port),因某些原因,我們先關(guān)閉,接著很快以相同的四元組建立一條新連接。本文前面介紹過,TCP連接由四元組唯一標(biāo)識,因此,在我們假設(shè)的情況中,TCP協(xié)議棧是無法區(qū)分前后兩條TCP連接的不同的,在它看來,這根本就是同一條連接,中間先釋放再建立的過程對其來說是“感知”不到的。這樣就可能發(fā)生這樣的情況:
前一條TCP連接由local peer發(fā)送的數(shù)據(jù)到達remote peer后,會被該remot peer的TCP傳輸層當(dāng)做當(dāng)前TCP連接的正常數(shù)據(jù)接收并向上傳遞至應(yīng)用層(而事實上,在我們假設(shè)的場景下,這些舊數(shù)據(jù)到達remote peer前,舊連接已斷開且一條由相同四元組構(gòu)成的新TCP連接已建立,因此,這些舊數(shù)據(jù)是不應(yīng)該被向上傳遞至應(yīng)用層的),從而引起數(shù)據(jù)錯亂進而導(dǎo)致各種無法預(yù)知的詭異現(xiàn)象。作為一種可靠的傳輸協(xié)議,TCP必須在協(xié)議層面考慮并避免這種情況的發(fā)生,這正是TIME_WAIT狀態(tài)存在的第2個原因。
設(shè)置2MSL使得A到B的舊連接發(fā)送的包失效(因為最大存活時間MSL),同時即使B回復(fù)了A的包,那也已經(jīng)失效了
3)總結(jié)?
具體而言,local peer主動調(diào)用close后,此時的TCP連接進入TIME_WAIT狀態(tài),處于該狀態(tài)下的TCP連接不能立即以同樣的四元組建立新連接,即發(fā)起active close的那方占用的local port在TIME_WAIT期間不能再被重新分配。由于TIME_WAIT狀態(tài)持續(xù)時間為2MSL,這樣保證了舊TCP連接雙工鏈路中的舊數(shù)據(jù)包均因過期(超過MSL)而消失,此后,就可以用相同的四元組建立一條新連接而不會發(fā)生前后兩次連接數(shù)據(jù)錯亂的情況。
?
1.防止上一次連接中的包,迷路后重新出現(xiàn),影響新連接(經(jīng)過2MSL,上一次連接中所有的重復(fù)包都會消失)
2. 可靠的關(guān)閉TCP連接。在主動關(guān)閉方發(fā)送的最后一個 ack(fin) ,有可能丟失,這時被動方會重新發(fā)fin, 如果這時主動方處于 CLOSED 狀態(tài),就會響應(yīng) rst 而不是 ack。所以主動方要處于 TIME_WAIT 狀態(tài),而不能是 CLOSED 。另外這么設(shè)計TIME_WAIT 會定時的回收資源,并不會占用很大資源的,除非短時間內(nèi)接受大量請求或者受到攻擊。
4.什么情況下會出現(xiàn)大量的time_wait狀態(tài)?
????????由于主動關(guān)閉TCP連接的一方才會進入TIME_WAIT狀態(tài),一般情況服務(wù)器端不會出現(xiàn)TIME_WAIT狀態(tài),因為大多數(shù)情況都是客戶端主動發(fā)起連接并主動關(guān)閉連接。但是某些服務(wù)如pop/smtp、ftp卻是服務(wù)端收到客戶端的QUIT命令后主動關(guān)閉連接,這就造成這類服務(wù)器上容易出現(xiàn)大量的TIME_WAIT狀態(tài)的連接,而且并發(fā)量越大處于此種狀態(tài)的連接越多。另外,對于被動關(guān)閉連接的服務(wù)在主動關(guān)閉客戶端非法請求或清理長時間不活動的連接時(這種情況很可能是客戶端程序忘記關(guān)閉連接)也會出現(xiàn)TIME_WAIT的狀態(tài)。(簡而言之,主動關(guān)閉連接一端會出現(xiàn)大量的TIME_WAIT狀態(tài))
5.什么情況下服務(wù)器會進行主動關(guān)閉的情況?
1)短連接的方式。如http服務(wù)器。
這確實是歷史包袱。原因很簡單,早先客戶端處理HTTP是單線程的、阻塞的,服務(wù)器端發(fā)送完信息后客戶端要一直等到信息處理完畢、渲染完畢,才能有處理能力來通知服務(wù)器處理完成。在當(dāng)時這個過程可以長達數(shù)分鐘,而且當(dāng)時服務(wù)器沒有能力去承載這么多等待響應(yīng)的連接(可以用Erlang計算一下這個延遲下需要滿足%99.9的可用性需要多么恐怖的硬件)。
所以解決方案就是服務(wù)器發(fā)送完之后就關(guān)閉連接,表明數(shù)據(jù)已經(jīng)發(fā)送完成。等客戶端接收到了所有信息,處理完畢,一看連接也關(guān)掉了,此時服務(wù)器早已在處理其他連接了。
另外這也是為什么有大量TIME_WAIT的原因,相比掛著連接等待客戶端關(guān)閉,服務(wù)器等待確認(rèn)TCP連接狀態(tài)要快太多了。
2)已經(jīng)進入了瓶頸。即連接數(shù)已經(jīng)達到了極限值。
?
6.出現(xiàn)太多TIME_WAIT可能導(dǎo)致的后果?(持續(xù)的到達一定量的高并發(fā)短連接,會使服務(wù)器因端口資源不足而拒絕為一部分客戶服務(wù))
?在高并發(fā)短連接的TCP服務(wù)器上,當(dāng)服務(wù)器處理完請求后立刻按照主動正常關(guān)閉連接。這個場景下,會出現(xiàn)大量socket處于TIMEWAIT狀態(tài)。如果客戶端的并發(fā)量持續(xù)很高,此時部分客戶端就會顯示連接不上。
我來解釋下這個場景。主動正常關(guān)閉TCP連接,都會出現(xiàn)TIMEWAIT。為什么我們要關(guān)注這個高并發(fā)短連接呢?有兩個方面需要注意:
?① 高并發(fā)可以讓服務(wù)器在短時間范圍內(nèi)同時占用大量端口,而端口有個0~65535的范圍,并不是很多,刨除系統(tǒng)和其他服務(wù)要用的,剩下的就更少了。
?②在這個場景中,短連接表示“業(yè)務(wù)處理+傳輸數(shù)據(jù)的時間 遠遠小于 TIMEWAIT超時的時間”的連接。這里有個相對長短的概念,比如,取一個web頁面,1秒鐘的http短連接處理完業(yè)務(wù),在關(guān)閉連接之后,這個業(yè)務(wù)用過的端口會停留在TIMEWAIT狀態(tài)幾分鐘,而這幾分鐘,其他HTTP請求來臨的時候是無法占用此端口的。單用這個業(yè)務(wù)計算服務(wù)器的利用率會發(fā)現(xiàn),服務(wù)器干正經(jīng)事的時間和端口(資源)被掛著無法被使用的時間的比例是 1:幾百,服務(wù)器資源嚴(yán)重浪費。(說個題外話,從這個意義出發(fā)來考慮服務(wù)器性能調(diào)優(yōu)的話,長連接業(yè)務(wù)的服務(wù)就不需要考慮TIMEWAIT狀態(tài)。同時,假如你對服務(wù)器業(yè)務(wù)場景非常熟悉,你會發(fā)現(xiàn),在實際業(yè)務(wù)場景中,一般長連接對應(yīng)的業(yè)務(wù)的并發(fā)量并不會很高)
? ? ?綜合這兩個方面,持續(xù)的到達一定量的高并發(fā)短連接,會使服務(wù)器因端口資源不足而拒絕為一部分客戶服務(wù)。
7.time_wait狀態(tài)如何避免?
首先服務(wù)器可以設(shè)置SO_REUSEADDR套接字選項來通知內(nèi)核,如果端口忙,但TCP連接位于TIME_WAIT狀態(tài)時可以重用端口。在一個非常有用的場景就是,如果你的服務(wù)器程序停止后想立即重啟,而新的套接字依舊希望使用同一端口,此時SO_REUSEADDR選項就可以避免TIME_WAIT狀態(tài)。
在很多場景中,為了能夠處理更多的用戶請求,一般取消timewait狀態(tài),用可靠性換取性能!
所以如果將大量CLOSE_WAIT的解決辦法總結(jié)為一句話那就是:查代碼。因為問題出在服務(wù)器程序里頭啊。
總結(jié)
以上是生活随笔為你收集整理的网络:TIME-WAIT的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络:TCP协议3次握手4次挥手
- 下一篇: AI 趋势