• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            tqsheng

            go.....
            隨筆 - 366, 文章 - 18, 評論 - 101, 引用 - 0
            數(shù)據(jù)加載中……

            從問題看本質(zhì): 研究TCP close_wait的內(nèi)幕

             * @author: ahuaxuan

             * @date: 2010-4-30

             */

             

            最近遇到的一個關(guān)于socket.close的問題,在某個應(yīng)用服務(wù)器出現(xiàn)的狀況(執(zhí)行netstat -np | grep tcp): 

            tcp        0      0 10.224.122.16:50158         10.224.112.58:8788          CLOSE_WAIT

            tcp        0      0 10.224.122.16:37655         10.224.112.58:8788          CLOSE_WAIT

            tcp        1      0 127.0.0.1:32713             127.0.0.1:8080              CLOSE_WAIT

            tcp       38      0 10.224.122.16:34538         10.224.125.42:443           CLOSE_WAIT

            tcp       38      0 10.224.122.16:33394         10.224.125.42:443           CLOSE_WAIT

            tcp        1      0 10.224.122.16:18882         10.224.125.10:80            CLOSE_WAIT

            tcp        1      0 10.224.122.16:18637         10.224.125.10:80            CLOSE_WAIT

            tcp        1      0 10.224.122.16:19655         10.224.125.12:80            CLOSE_WAIT

            ........................................

             

            總共出現(xiàn)了200個CLOSE_WAIT的socket.而且這些socket長時間得不到釋放.下面我們來看看為什么會出現(xiàn)這種大量socket的CLOSE_WAIT情況

             

            首先我們要搞清楚的是,這個socket是誰發(fā)起的,我們可以看到122.16這臺機器開了很多端口,而且端口號都很大,125.12 或者125.10上的端口都是很常見服務(wù)器端口,所以122.16上這么多CLOSE_WAIT

            的socket是由122.16開啟的,換句話說這臺機器是傳統(tǒng)的客戶端,它會主動的請求其他機器的服務(wù)端口.

             

            要搞清楚為什么會出現(xiàn)CLOSE_WAIT,那么首先我們必須要清楚CLOSE_WAIT的機制和原理.

             

            假設(shè)我們有一個client, 一個server.

             

            當(dāng)client主動發(fā)起一個socket.close()這個時候?qū)?yīng)TCP來說,會發(fā)生什么事情呢?如下圖所示.

             

            ?

             

             

            client首先發(fā)送一個FIN信號給server, 這個時候client變成了FIN_WAIT_1的狀態(tài), server端收到FIN之后,返回ACK,然后server端的狀態(tài)變成了CLOSE_WAIT.

            接著server端需要發(fā)送一個FIN給client,然后server端的狀態(tài)變成了LAST_ACK,接著client返回一個ACK,然后server端的socket就被成功的關(guān)閉了.

             

            從這里可以看到,如果由客戶端主動關(guān)閉一鏈接,那么客戶端是不會出現(xiàn)CLOSE_WAIT狀態(tài)的.客戶端主動關(guān)閉鏈接,那么Server端將會出現(xiàn)CLOSE_WAIT的狀態(tài).

            而我們的服務(wù)器上,是客戶端socket出現(xiàn)了CLOSE_WAIT,由此可見這個是由于server主動關(guān)閉了server上的socket.

             

            那么當(dāng)server主動發(fā)起一個socket.close(),這個時候又發(fā)生了一些什么事情呢.

            ?

             

            從圖中我們可以看到,如果是server主動關(guān)閉鏈接,那么Client則有可能進(jìn)入CLOSE_WAIT,如果Client不發(fā)送FIN包,那么client就一直會處在CLOSE_WAIT狀態(tài)(后面我們可以看到有參數(shù)可以調(diào)整這個時間).

             

            那么現(xiàn)在我們要搞清楚的是,在第二中場景中,為什么Client不發(fā)送FIN包給server.要搞清楚這個問題,我們首先要搞清楚server是怎么發(fā)FIN包給client的,其實server就是調(diào)用了

            socket.close方法而已,也就是說如果要client發(fā)送FIN包,那么client就必須調(diào)用socket.close,否則就client就一直會處在CLOSE_WAIT(但事實上不同操作系統(tǒng)這點的實現(xiàn)還不一樣,

            在ahuaxuan(ahuaxuan.iteye.com)的例子中也出現(xiàn)了這樣的case).

             

            下面我們來做幾個實驗

            實驗一:

            環(huán)境:

            服務(wù)器端:win7+tomcat,tomcat的keep-alive的時間為默認(rèn)的15s.

            客戶端:mac os

            實驗步驟:服務(wù)器啟動后,客戶端向服務(wù)器發(fā)送一個get請求,然后客戶端阻塞,等待服務(wù)器端的socket超時.通過netstat -np tcp可以看到的情況是發(fā)送get請求時,服務(wù)器和客戶端鏈接是ESTABLISHED, 15s之后,客戶端變成了CLOSE_WAIT,而服務(wù)器端變成了FIN_WAIT_2.這一點也在我們的預(yù)料之中,而這個時候由于客戶端線程阻塞,客戶端socket空置在那里,不做任何操作,2分鐘過后,這個鏈接不管是在win7上,還是在mac os都看不到了.可見,FIN_WAIT_2或者CLOSE_WAIT有一個timeout.在后面的實驗,可以證明,在這個例子中,其實是FIN_WAIT_2有一個超時,一旦過了2分鐘,那么win7會發(fā)一個RST給mac os要求關(guān)閉雙方的socket.

             

            實驗二

            服務(wù)器端:ubuntu9.10+tomcat,tomcat的keep-alive的時間為默認(rèn)的15s.

            客戶端:mac os

            實驗步驟:服務(wù)器啟動后,客戶端向服務(wù)器發(fā)送一個get請求,然后客戶端阻塞,等待服務(wù)器端的socket超時.通過netstat -np tcp(ubuntu使用netstat -np|grep tcp)可以看到的情況是發(fā)送get請求時,服務(wù)器和客戶端鏈接是ESTABLISHED, 15s之后,客戶端變成了CLOSE_WAIT,而服務(wù)器端變成了FIN_WAIT_2.這一點也也在我們的預(yù)料之中,而這個時候由于客戶端線程阻塞,客戶端socket空置在那里,不做任何操作,1分鐘過后,ubuntu上的那個socket不見了,但是mac os上的socket還在,而且還是CLOSE_WAIT,這說明,FIN_WAIT_2確實有一個超時時間,win7上的超時操作可以關(guān)閉mac os上的socket,而ubuntu上的FIN_WAIT_2超時操作卻不能關(guān)閉mac os上的socket(其狀一直是CLOSE_WAIT).

             

            實驗三

            服務(wù)器端:mac os+tomcat,tomcat的keep-alive的時間為默認(rèn)的15s.

            客戶端:mac os

            實驗步驟:服務(wù)器啟動后,客戶端向服務(wù)器發(fā)送一個get請求,然后客戶端阻塞,等待服務(wù)器端的socket超時.通過netstat -np tcp可以看到的情況是發(fā)送get請求時,服務(wù)器和客戶端鏈接是ESTABLISHED, 15s之后,客戶端變成了CLOSE_WAIT,而服務(wù)器端變成了FIN_WAIT_2.這一點也在我們的預(yù)料之中,而這個時候由于客戶端線程阻塞,客戶端socket空置在那里,不做任何操作,4分鐘過后,mac os服務(wù)器端上的那個socket不見了,但是mac os客戶端上的socket還在,而且還是CLOSE_WAIT,這說明,FIN_WAIT_2確實有一個超時時間,win7上的超時操作可以關(guān)閉mac os上的socket,而ubuntu和mac os上的FIN_WAIT_2超時操作卻不能關(guān)閉mac os上的socket.

             

             

             

            總結(jié), 當(dāng)服務(wù)器的內(nèi)核不一樣上FIN_WAIT_2的超時時間和操作是不一樣的.

            經(jīng)查:控制FIN_WAIT_2的參數(shù)為:

            /proc/sys/net/ipv4/tcp_fin_timeout

            如 果套接字由本端要求關(guān)閉,這個參數(shù)決定了它保持在FIN-WAIT-2狀態(tài)的時間。對端可以出錯并永遠(yuǎn)不關(guān)閉連接,甚至意外當(dāng)機。缺省值是60秒。2.2 內(nèi)核的通常值是180秒,你可以按這個設(shè)置,但要記住的是,即使你的機器是一個輕載的WEB服務(wù)器,也有因為大量的死套接字而內(nèi)存溢出的風(fēng)險,F(xiàn)IN- WAIT-2的危險性比FIN-WAIT-1要小,因為它最多只能吃掉1.5K內(nèi)存,但是它們的生存期長些。參見tcp_max_orphans。

             

            實驗四

            服務(wù)器端:ubuntu9.10+tomcat,tomcat的keep-alive的時間為默認(rèn)的15s.

            客戶端:mac os

            實驗步驟:服務(wù)器啟動后,客戶端向服務(wù)器發(fā)送一個get請求,然后關(guān)閉客戶端關(guān)閉socket.通過netstat -np tcp可以看到的情況是發(fā)送get請求時,服務(wù)器和客戶端鏈接是ESTABLISHED, 客戶端拿到數(shù)據(jù)之后,客戶端變成了TIME_WAIT,而服務(wù)器端變成了已經(jīng)看不到這個socket了.這一點也也在我們的預(yù)料之中,誰主動關(guān)閉鏈接,那么誰就需要進(jìn)入TIME_WAIT狀態(tài)(除非他的FIN_WAIT_2超時了),大約1分鐘之后這個socket在客戶端也消失了.

             

            實驗證明TIME_WAIT的狀態(tài)會存在一段時間,而且在這個時間端里,這個FD是不能被回收的.

             

            但是我們的問題是客戶端有很多CLOSE_WAIT,而且我們的服務(wù)器不是windows,而是linux,所以CLOSE_WAIT有沒有超時時間呢,肯定有,而且默認(rèn)情況下這個超時時間應(yīng)該是比較大的.否則不會一下子看到兩百個CLOSE_WAIT的狀態(tài).

             

            客戶端解決方案:

             

            1.由于socket.close()會導(dǎo)致FIN信號,而client的socket CLOSE_WAIT就是因為該socket該關(guān)的時候,我們沒有關(guān),所以我們需要一個線程池來檢查空閑連接中哪些進(jìn)入了超時狀態(tài)(idleTIME),但進(jìn)入超時

            的socket未必是CLOSE_WAIT的狀態(tài)的.不過如果我們把空閑超時的socket關(guān)閉,那么CLOSE_WAIT的狀態(tài)就會消失.(問題:像HttpClient這樣的工具包中,如果要檢查鏈接池,那么則需要鎖定整個池,而這個時候,用戶請求獲取connection的操作只能等待,在高并發(fā)的時候會造成程序響應(yīng)速度下降,具體參考IdleConnectionTimeoutThread.java(HttpClient3.1))

             

            2.經(jīng)查,其實有參數(shù)可以調(diào)整CLOSE_WAIT的持續(xù)時間,如果我們改變這個時間,那么可以讓CLOSE_WAIT只保持很短的時間(當(dāng)然這個參數(shù)不只作用在CLOSE_WAIT上,縮短這個時間可能會帶來其他的影響).在客戶端機器上修改如下:

            sysctl -w net.ipv4.tcp_keepalive_time=60(缺省是2小時,現(xiàn)在改成了60秒)

            sysctl -w net.ipv4.tcp_keepalive_probes=2

            sysctl -w net.ipv4.tcp_keepalive_intvl=2

            我們將CLOSE_WAIT的檢查時間設(shè)置為30s,這樣一個CLOSE_WAIT只會存在30S.

             

            3. 當(dāng)然,最重要的是我們要檢查客戶端鏈接的空閑時間,空閑時間可以由客戶端自行定義,比如idleTimeout,也可由服務(wù)器來決定,服務(wù)器只需要每次在response.header中加入一個頭信息,比如說名字叫做timeout頭,當(dāng)然一般情況下我們會用keep-alive這個頭字段, 如果服務(wù)器設(shè)置了該字段,那么客戶端拿到這個屬性之后,就知道自己的connection最大的空閑時間,這樣不會由于服務(wù)器關(guān)閉socket,而導(dǎo)致客戶端socket一直close_wait在那里.

             

            服務(wù)器端解決方案

             

            4.前面講到客戶端出現(xiàn)CLOSE_WAIT是由于服務(wù)器端Socket的讀超時,也是TOMCAT中的keep-alive參數(shù).那么如果我們把這個超時時間設(shè)置的長點,會有什么影響?

            如果我們的tomcat既服務(wù)于瀏覽器,又服務(wù)于其他的APP,而且我們把connection的keep-alive時間設(shè)置為10分鐘,那么帶來的后果是瀏覽器打開一個頁面,然后這個頁面一直不關(guān)閉,那么服務(wù)器上的socket也不能關(guān)閉,它所占用的FD也不能服務(wù)于其他請求.如果并發(fā)一高,很快服務(wù)器的資源將會被耗盡.新的請求再也進(jìn)不來. 那么如果把keep-alive的時間設(shè)置的短一點呢,比如15s? 那么其他的APP來訪問這個服務(wù)器的時候,一旦這個socket, 15s之內(nèi)沒有新的請求,那么客戶端APP的socket將出現(xiàn)大量的CLOSE_WAIT狀態(tài).

            所以如果出現(xiàn)這種情況,建議將你的server分開部署,服務(wù)于browser的部署到單獨的JVM實例上,保持keep-alive為15s,而服務(wù)于架構(gòu)中其他應(yīng)用的功能部署到另外的JVM實例中,并且將keep-alive的時間設(shè)置的更

            長,比如說1個小時.這樣客戶端APP建立的connection,如果在一個小時之內(nèi)都沒有重用這條connection,那么客戶端的socket才會進(jìn)入CLOSE_WAIT的狀態(tài).針對不同的應(yīng)用場景來設(shè)置不同的keep-alive時間,可以幫助我們提高程序的性能.

             

            5.如果我們的應(yīng)用既服務(wù)于瀏覽器,又服務(wù)于其他的APP,那么我們還有一個終極解決方案.

            那就是配置多個connector, 如下:

            <!-- for browser -->

             <Connector port="8080" protocol="HTTP/1.1" 

                           connectionTimeout="20000" 

                           redirectPort="8443" />

             

            <!-- for other APP -->

            <Connector port="8081" protocol="HTTP/1.1" 

                           connectionTimeout="20000" 

                           redirectPort="8443" keepAliveTimeout="330000" />

             

            訪問的時候,瀏覽器使用8080端口,其他的APP使用8081端口.這樣可以保證瀏覽器請求的socket在15s之內(nèi)如果沒有再次使用,那么tomcat會主動關(guān)閉該socket,而其他APP請求的socket在330s之內(nèi)沒有使用,才關(guān)閉該socket,這樣做可以大大減少其他APP上出現(xiàn)CLOSE_WAIT的幾率.

             

            你一定會問,如果我不設(shè)置keepAliveTimeout又怎么樣呢,反正客戶端有idleTimeout,客戶端的close_wait不會持續(xù)太長時間,請注意看上圖中標(biāo)紅的地方,一個是close_wait,還有一個是time_wait狀態(tài),也就是說誰主動發(fā)起請求,那么它將會最終進(jìn)入time_wait狀態(tài),據(jù)說windows上這個time_wait將持續(xù)4分鐘,我在linux上的測試表明,linux上它大概是60s左右,也就是說高并發(fā)下,也就是服務(wù)器也需要過60s左右才能真正的釋放這個FD.所以我們?nèi)绻峁﹉ttp服務(wù)給其他APP,那么我們最好讓客戶端優(yōu)先關(guān)閉socket,也就是將客戶端的idleTimeout設(shè)置的比server的keepalivetimeout小一點.這樣保證time_wait出現(xiàn)在客戶端. 而不是資源較為緊張的服務(wù)器端.

             

            總結(jié):

                   本文中ahuaxuan給大家揭示了TCP層client和server端socket關(guān)閉的一般流程,并且指出異常情況下client和server端各自會發(fā)生的情況,包含了在不同平臺上出現(xiàn)了的不同情況, 同時說明了在應(yīng)用層上我們可以做什么樣的邏輯來保證socket關(guān)閉時對server端帶來最小的影響.

             

             

             

            下面是網(wǎng)上找到的一些資料:

             

             寫道



            /proc/sys/net/ipv4/tcp_keepalive_time
當(dāng)keepalive起用的時候,TCP發(fā)送keepalive消息的頻度。缺省是2小時。
            
/proc/sys/net/ipv4/tcp_keepalive_intvl
當(dāng)探測沒有確認(rèn)時,重新發(fā)送探測的頻度。缺省是75秒。
            
/proc/sys/net/ipv4/tcp_keepalive_probes
在認(rèn)定連接失效之前,發(fā)送多少個TCP的keepalive探測包。缺省值是9。這個值乘以tcp_keepalive_intvl之后決定了,一個連接發(fā)送了keepalive之后可以有多少時間沒有回應(yīng)。


            /proc/sys/net/ipv4/tcp_max_orphans
            系 統(tǒng)中最多有多少個TCP套接字不被關(guān)聯(lián)到任何一個用戶文件句柄上。如果超過這個數(shù)字,孤兒連接將即刻被復(fù)位并打印出警告信息。這個限制僅僅是為了防止簡單的DoS攻擊,你絕對不能過分依靠它或者人為地減小這個值,更應(yīng)該增加這個值(如果增加了內(nèi)存之后)。This limit exists only to prevent simple DoS attacks, you _must_ not rely on this or lower the limit artificially, but rather increase it (probably, after increasing installed memory), if network conditions require more than default value, and tune network services to linger and kill such states more aggressively. 讓我再次提醒你:每個孤兒套接字最多能夠吃掉你64K不可交換的內(nèi)存。

            /proc/sys/net/ipv4/tcp_orphan_retries
            本端試圖關(guān)閉TCP連接之前重試多少次。缺省值是7,相當(dāng)于50秒~16分鐘(取決于RTO)。如果你的機器是一個重載的WEB服務(wù)器,你應(yīng)該考慮減低這個值,因為這樣的套接字會消耗很多重要的資源。參見tcp_max_orphans。

            /proc/sys/net/ipv4/tcp_max_syn_backlog
            記 錄的那些尚未收到客戶端確認(rèn)信息的連接請求的最大值。對于有128M內(nèi)存的系統(tǒng)而言,缺省值是1024,小內(nèi)存的系統(tǒng)則是128。如果服務(wù)器不堪重負(fù),試 試提高這個值。注意!如果你設(shè)置這個值大于1024,最好同時調(diào)整include/net/tcp.h中的TCP_SYNQ_HSIZE,以保證 TCP_SYNQ_HSIZE*16 ≤tcp_max_syn_backlo,然后重新編譯內(nèi)核。

            /proc/sys/net/ipv4/tcp_max_tw_buckets
            系 統(tǒng)同時保持timewait套接字的最大數(shù)量。如果超過這個數(shù)字,time-wait套接字將立刻被清除并打印警告信息。這個限制僅僅是為了防止簡單的 DoS攻擊,你絕對不能過分依靠它或者人為地減小這個值,如果網(wǎng)絡(luò)實際需要大于缺省值,更應(yīng)該增加這個值(如果增加了內(nèi)存之后)。

            posted on 2012-08-27 16:39 tqsheng 閱讀(218) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久精品国内一区二区三区| 久久国产热这里只有精品| 久久久久久久尹人综合网亚洲 | 国产精品激情综合久久| 久久综合丁香激情久久| 热综合一本伊人久久精品 | 一本一本久久A久久综合精品 | 国产精品福利一区二区久久| 伊色综合久久之综合久久| 丁香久久婷婷国产午夜视频| 久久久无码精品亚洲日韩按摩| 久久狠狠一本精品综合网| 狠狠色综合久久久久尤物| 久久成人永久免费播放| 欧美国产成人久久精品| 亚洲欧洲精品成人久久奇米网| 一本综合久久国产二区| 国产精品久久久久久久人人看 | 久久免费高清视频| 72种姿势欧美久久久久大黄蕉| 婷婷伊人久久大香线蕉AV| 国产精品久久久久国产A级| 国产999精品久久久久久| 久久久精品人妻无码专区不卡| 品成人欧美大片久久国产欧美... 品成人欧美大片久久国产欧美 | 蜜桃麻豆www久久国产精品| 久久久久高潮综合影院| 亚洲精品综合久久| 久久精品99无色码中文字幕| 久久精品国内一区二区三区| 色综合久久中文字幕无码| 欧美伊人久久大香线蕉综合 | 婷婷久久综合| 午夜精品久久久内射近拍高清 | 久久精品无码一区二区无码| 精品国产一区二区三区久久久狼| 狠狠色丁香久久婷婷综合_中| 亚洲AⅤ优女AV综合久久久| 亚洲国产成人久久综合区| 人妻精品久久无码专区精东影业| 天堂久久天堂AV色综合|