摘要:服務(wù)器出現(xiàn)異常最長(zhǎng)出現(xiàn)的狀況是服務(wù)器保持了大量的狀態(tài)。此時(shí)主動(dòng)關(guān)閉一方必須保持一個(gè)有效的狀態(tài)下維持狀態(tài)信息,以便可以重發(fā)。這就意味著,一個(gè)成功建立的連接,必須使得之前網(wǎng)絡(luò)中殘余的數(shù)據(jù)報(bào)都丟失了。,維持這些狀態(tài)給服務(wù)器端帶來(lái)巨大的負(fù)擔(dān)。
查看TIME_WAIT和CLOSE_WAIT數(shù)的命令:
netstat -n | awk "/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}"
它會(huì)顯示例如下面的信息:
TIME_WAIT 、CLOSE_WAIT 、FIN_WAIT1 、ESTABLISHED 、SYN_RECV 、LAST_ACK
常用的三個(gè)狀態(tài)是:ESTABLISHED表示正在通信 、TIME_WAIT表示主動(dòng)關(guān)閉、CLOSE_WAIT表示被動(dòng)關(guān)閉。
服務(wù)器出現(xiàn)異常最長(zhǎng)出現(xiàn)的狀況是:
服務(wù)器保持了大量的TIME_WAIT狀態(tài)。
服務(wù)器保持了大量的CLOSE_WAIT狀態(tài)。
我們也都知道Linux系統(tǒng)中分給每個(gè)用戶的文件句柄數(shù)是有限的,而TIME_WAIT和CLOSE_WAIT這兩種狀態(tài)如果一直被保持,那么意味著對(duì)應(yīng)數(shù)目的通道(此處應(yīng)理解為socket,一般一個(gè)socket會(huì)占用服務(wù)器端一個(gè)端口,服務(wù)器端的端口最大數(shù)是65535)一直被占用,一旦達(dá)到了上限,則新的請(qǐng)求就無(wú)法被處理,接著就是大量Too Many Open Files異常,然后tomcat、nginx、apache崩潰。。。
下面來(lái)討論這兩種狀態(tài)的處理方法,網(wǎng)絡(luò)上也有很多資料把這兩種情況混為一談,認(rèn)為優(yōu)化內(nèi)核參數(shù)就可以解決,其實(shí)這是不恰當(dāng)?shù)摹?yōu)化內(nèi)核參數(shù)在一定程度上能解決time_wait過(guò)多的問(wèn)題,但是應(yīng)對(duì)close_wait還得從應(yīng)用程序本身出發(fā)。
服務(wù)器保持了大量的time_wait狀態(tài)
這種情況比較常見(jiàn),一般會(huì)出現(xiàn)在爬蟲(chóng)服務(wù)器和web服務(wù)器(如果沒(méi)做內(nèi)核參數(shù)優(yōu)化的話)上,那么這種問(wèn)題是怎么產(chǎn)生的呢?
從上圖可以看出time_wait是主動(dòng)關(guān)閉連接的一方保持的狀態(tài),對(duì)于爬蟲(chóng)服務(wù)器來(lái)說(shuō)它自身就是客戶端,在完成一個(gè)爬取任務(wù)后就會(huì)發(fā)起主動(dòng)關(guān)閉連接,從而進(jìn)入time_wait狀態(tài),然后保持這個(gè)狀態(tài)2MSL時(shí)間之后,徹底關(guān)閉回收資源。這里為什么會(huì)保持資源2MSL時(shí)間呢?這也是TCP/IP設(shè)計(jì)者規(guī)定的。
TCP要保證在所有可能的情況下使得所有的數(shù)據(jù)都能夠被正確送達(dá)。當(dāng)你關(guān)閉一個(gè)socket時(shí),主動(dòng)關(guān)閉一端的socket將進(jìn)入TIME_WAIT狀 態(tài),而被動(dòng)關(guān)閉一方則轉(zhuǎn)入CLOSED狀態(tài),這的確能夠保證所有的數(shù)據(jù)都被傳輸。當(dāng)一個(gè)socket關(guān)閉的時(shí)候,是通過(guò)兩端四次握手完成的,當(dāng)一端調(diào)用 close()時(shí),就說(shuō)明本端沒(méi)有數(shù)據(jù)要發(fā)送了。這好似看來(lái)在握手完成以后,socket就都可以處于初始的CLOSED狀態(tài)了,其實(shí)不然。原因是這樣安排狀態(tài)有兩個(gè)問(wèn)題, 首先,我們沒(méi)有任何機(jī)制保證最后的一個(gè)ACK能夠正常傳輸,第二,網(wǎng)絡(luò)上仍然有可能有殘余的數(shù)據(jù)包(wandering duplicates),我們也必須能夠正常處理。
TIMEWAIT就是為了解決這兩個(gè)問(wèn)題而生的。
假設(shè)最后的一個(gè)ACK丟失,那么被動(dòng)關(guān)閉一方收不到這最后一個(gè)ACK則會(huì)重發(fā)FIN。此時(shí)主動(dòng)關(guān)閉一方必須保持一個(gè)有效的(time_wait狀態(tài)下維持)狀態(tài)信息,以便可以重發(fā)ACK。如果主動(dòng)關(guān)閉的socket不維持這種狀態(tài)而是進(jìn)入close狀態(tài),那么主動(dòng)關(guān)閉的一方在收到被動(dòng)關(guān)閉方重新發(fā)送的FIN時(shí)則響應(yīng)給被動(dòng)方一個(gè)RST。被動(dòng)方收到這個(gè)RST后會(huì)認(rèn)為此次回話出錯(cuò)了。所以如果TCP想要完成必要的操作而終止雙方的數(shù)據(jù)流傳輸,就必須完全正確的傳輸四次握手的四步,不能有任何的丟失。這就是為什么在socket在關(guān)閉后,任然處于time_wait狀態(tài)的第一個(gè)原因。因?yàn)樗却赡艹霈F(xiàn)的錯(cuò)誤(被動(dòng)關(guān)閉端沒(méi)有接收到最后一個(gè)ACK),以便重發(fā)ACK。
假設(shè)目前連接的通信雙方都調(diào)用了close(),雙方同時(shí)進(jìn)入closed的終結(jié)狀態(tài),而沒(méi)有走 time_wait狀態(tài)。則會(huì)出現(xiàn)如下問(wèn)題:假如現(xiàn)在有一個(gè)新的連接建立起來(lái),使用的IP地址與之前的端口完全相同,現(xiàn)在建立的一個(gè)連接是之前連接的完全復(fù)用,我們還假定之前連接中有數(shù)據(jù)報(bào)殘存在網(wǎng)絡(luò)之中,這樣的話現(xiàn)在的連接收到的數(shù)據(jù)有可能是之前連接的報(bào)文。為了防止這一點(diǎn)。TCP不允許新的連接復(fù)用time_wait狀態(tài)下的socket。處于time_wait狀態(tài)的socket在等待2MSL時(shí)間后(之所以是兩倍的MSL,是由于MSL是一個(gè)數(shù)據(jù)報(bào)在網(wǎng)絡(luò)中單向發(fā)出 到認(rèn)定丟失的時(shí)間,即(Maximum Segment Lifetime)報(bào)文最長(zhǎng)存活時(shí)間,一個(gè)數(shù)據(jù)報(bào)有可能在發(fā)送途中或是其響應(yīng)過(guò)程中成為殘余數(shù)據(jù)報(bào),確認(rèn)一個(gè)數(shù)據(jù)報(bào)及其響應(yīng)的丟棄需要兩倍的MSL),將會(huì)轉(zhuǎn)為closed狀態(tài)。這就意味著,一個(gè)成功建立的連接,必須使得之前網(wǎng)絡(luò)中殘余的數(shù)據(jù)報(bào)都丟失了。
再引用網(wǎng)絡(luò)中的一段話:
值得一說(shuō)的是,基于TCP的http協(xié)議,一般(此處為什么說(shuō)一般呢,因?yàn)楫?dāng)你在keepalive時(shí)間內(nèi) 主動(dòng)關(guān)閉對(duì)服務(wù)器端的連接時(shí),那么主動(dòng)關(guān)閉端就是客戶端,否則客戶端就是被動(dòng)關(guān)閉端。下面的爬蟲(chóng)例子就是這種情況)主動(dòng)關(guān)閉tcp一端的是server端,這樣server端就會(huì)進(jìn)入time_wait狀態(tài),可想而知,對(duì)于訪問(wèn)量大的web服務(wù)器,會(huì)存在大量的time_wait狀態(tài),假如server一秒鐘接收1000個(gè)請(qǐng)求,那么就會(huì)積壓240*1000=240000個(gè)time_wait狀態(tài)。(RFC 793中規(guī)定MSL為2分鐘,實(shí)際應(yīng)用中常用的是30秒,1分鐘和2分鐘等。),維持這些狀態(tài)給服務(wù)器端帶來(lái)巨大的負(fù)擔(dān)。當(dāng)然現(xiàn)代操作系統(tǒng)都會(huì)用快速的查找算法來(lái)管理這些 TIME_WAIT,所以對(duì)于新的 TCP連接請(qǐng)求,判斷是否hit中一個(gè)TIME_WAIT不會(huì)太費(fèi)時(shí)間,但是有這么多狀態(tài)要維護(hù)總是不好。
HTTP協(xié)議1.1版本規(guī)定default行為是keep-Alive,也就是會(huì)重用tcp連接傳輸多個(gè) request/response。之所以這么做的主要原因是發(fā)現(xiàn)了我們上面說(shuō)的這個(gè)問(wèn)題。
服務(wù)器保持了大量的close_wait狀態(tài)
time_wait問(wèn)題可以通過(guò)調(diào)整內(nèi)核參數(shù)和適當(dāng)?shù)脑O(shè)置web服務(wù)器的keep-Alive值來(lái)解決。因?yàn)閠ime_wait是自己可控的,要么就是對(duì)方連接的異常,要么就是自己沒(méi)有快速的回收資源,總之不是由于自己程序錯(cuò)誤引起的。但是close_wait就不一樣了,從上圖中我們可以看到服務(wù)器保持大量的close_wait只有一種情況,那就是對(duì)方發(fā)送一個(gè)FIN后,程序自己這邊沒(méi)有進(jìn)一步發(fā)送ACK以確認(rèn)。換句話說(shuō)就是在對(duì)方關(guān)閉連接后,程序里沒(méi)有檢測(cè)到,或者程序里本身就已經(jīng)忘了這個(gè)時(shí)候需要關(guān)閉連接,于是這個(gè)資源就一直被程序占用著。這個(gè)時(shí)候快速的解決方法是:
關(guān)閉正在運(yùn)行的程序,這個(gè)需要視業(yè)務(wù)情況而定。
盡快的修改程序里的bug,然后測(cè)試提交到線上服務(wù)器。
注:
直到寫(xiě)這篇文章的時(shí)候我才完全弄明白之前工作中遇到的一個(gè)問(wèn)題。程序員寫(xiě)了爬蟲(chóng)(php)運(yùn)行在采集服務(wù)器A上,程序去B服務(wù)器上采集資源,但是A服務(wù)器很快就發(fā)現(xiàn)出現(xiàn)了大量的close_wait狀態(tài)的連接。后來(lái)手動(dòng)檢查才發(fā)現(xiàn)這些處于close_wait狀態(tài)的請(qǐng)求結(jié)果都是404,那就說(shuō)明B服務(wù)器上沒(méi)有要請(qǐng)求的資源。
下面引用網(wǎng)友分析的結(jié)論:
服 務(wù)器A是一臺(tái)爬蟲(chóng)服務(wù)器,它使用簡(jiǎn)單的HttpClient去請(qǐng)求資源服務(wù)器B上面的apache獲取文件資源,正常情況下,如果請(qǐng)求成功,那么在抓取完 資源后,服務(wù)器A會(huì)主動(dòng)發(fā)出關(guān)閉連接的請(qǐng)求,這個(gè)時(shí)候就是主動(dòng)關(guān)閉連接,服務(wù)器A的連接狀態(tài)我們可以看到是TIME_WAIT。如果一旦發(fā)生異常呢?假設(shè) 請(qǐng)求的資源服務(wù)器B上并不存在,那么這個(gè)時(shí)候就會(huì)由服務(wù)器B發(fā)出關(guān)閉連接的請(qǐng)求,服務(wù)器A就是被動(dòng)的關(guān)閉了連接,如果服務(wù)器A被動(dòng)關(guān)閉連接之后程序員忘了 讓HttpClient釋放連接,那就會(huì)造成CLOSE_WAIT的狀態(tài)了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/39892.html
摘要:服務(wù)器出現(xiàn)異常最長(zhǎng)出現(xiàn)的狀況是服務(wù)器保持了大量的狀態(tài)。此時(shí)主動(dòng)關(guān)閉一方必須保持一個(gè)有效的狀態(tài)下維持狀態(tài)信息,以便可以重發(fā)。這就意味著,一個(gè)成功建立的連接,必須使得之前網(wǎng)絡(luò)中殘余的數(shù)據(jù)報(bào)都丟失了。,維持這些狀態(tài)給服務(wù)器端帶來(lái)巨大的負(fù)擔(dān)。 showImg(https://segmentfault.com/img/bV9DQk?w=732&h=563); showImg(https://se...
摘要:無(wú)法形容,直接對(duì)產(chǎn)生了滿分好感于是直接打開(kāi)源碼目錄全局搜,找到,如下一段注釋掉了上面這些,跑起來(lái)沒(méi)有問(wèn)題,這樣的問(wèn)題就解決了。那么查一下,有說(shuō)設(shè)置注冊(cè)表的感覺(jué)并不是解決辦法實(shí)測(cè)也不能解決問(wèn)題。 背景 我司的軟件在一個(gè)客戶處測(cè)試功能和性能,這個(gè)客戶比較特殊: 他們客戶端是很舊的java代碼,且要求不能改動(dòng),客戶端的主要業(yè)務(wù)簡(jiǎn)單說(shuō)就是上傳下載文件 他們提供了客戶端demo,http請(qǐng)求是...
摘要:無(wú)法形容,直接對(duì)產(chǎn)生了滿分好感于是直接打開(kāi)源碼目錄全局搜,找到,如下一段注釋掉了上面這些,跑起來(lái)沒(méi)有問(wèn)題,這樣的問(wèn)題就解決了。那么查一下,有說(shuō)設(shè)置注冊(cè)表的感覺(jué)并不是解決辦法實(shí)測(cè)也不能解決問(wèn)題。 背景 我司的軟件在一個(gè)客戶處測(cè)試功能和性能,這個(gè)客戶比較特殊: 他們客戶端是很舊的java代碼,且要求不能改動(dòng),客戶端的主要業(yè)務(wù)簡(jiǎn)單說(shuō)就是上傳下載文件 他們提供了客戶端demo,http請(qǐng)求是...
閱讀 2671·2021-11-25 09:43
閱讀 2579·2021-11-22 09:34
閱讀 2823·2021-11-12 10:34
閱讀 1431·2021-10-20 13:46
閱讀 2300·2019-08-30 13:21
閱讀 929·2019-08-30 11:21
閱讀 483·2019-08-30 11:20
閱讀 2186·2019-08-29 17:20