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