TCP 連接的 TIME_WAIT 過多 導致 Tomcat 假死


最近系統二次開發之后,發現使用的 Tomcat 7 會經常假死。前端點擊頁面無任何反應,打開firebug,很多鏈接一直在等待服務器的反應。查看服務器的狀態,CPU占用很少,最多不超過10%,一般只有2%,3%左右,內存占用倒是接近80, 90%。一開始懷疑是tomcat內存配置不夠,但是打開 jvisualvm.exe 分析,發現Tomcat 占用的堆內存沒有什么問題。因為是假死,所以最后懷疑到 tomcat的 鏈接數和 數據庫的鏈接數的配置估計太小了。netstat -na 結果頁顯示很多time_wait.

查看各種狀態的網絡連接的數量:

1)Linux 使用命令:netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

上面的命令可以查出各種狀態的網絡連接的數量
2)windows使用命令:

netstat -n |find /i "time_wait" /c

netstat -n |find /i "close_wait" /c

netstat -n |find /i "established" /c

windows下沒有awk,所以要一個一個狀態的統計它們的數量。

結果是:

1)TIME_WAIT: 狀態的連接達到了 709

sql server占用的TIME_WAIT最多,還有nginx, tomcat都有一些處於 TIME_WAIT狀態。

2)並且最大的端口達到了 65327 ,六萬多,幾乎接近端口的最大值 65535.

因為是 Windows server 2008,不同Linux下的TCP的調優。

解決方法:將 TcpTimedWaitDelay 調到 30S,讓 TIME_WAIT 狀態的維持最多30S,默認是4分鍾。

如何查看或設置TcpTimedWaitDelay

cmd中運行 regedit 命令,找到 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/ Services/TCPIP/Parameters 注冊表子鍵

看看有沒有  TcpTimedWaitDelay 項,有的話直接修改,沒有的話創建一個並創建名為 TcpTimedWaitDelay 的新 REG_DWORD 值。 將此值設置為十進制 30,其為十六進制 0x0000001e。該值將等待時間設置為 30 秒。 停止並重新啟動系統。 缺省值:0xF0,它將等待時間設置為 240 秒(4 分鍾)。 建議值:最小值為 0x1E,它將等待時間設置為 30 秒。

修改之后,重啟系統,在觀察,TIME_WAIT在100左右徘徊。效果還是立竿見影的。幾天來一直再也沒有出現Tomcat假死的情況。

 

當然也可以同時 增大 MaxUserPort 的數值(2008最大值好像是 65535):

MaxUserPort :確定在應用程序從系統請求可用用戶端口時,TCP/IP 可指定的最高端口號。默認是65535,可以調到10萬.

如何查看或設置: 使用 regedit 命令訪問 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/ Services/TCPIP/Parameters 注冊表子鍵並創建名為 MaxUserPort 的新 REG_DWORD 值,比如設置成200000。

參考:http://www.cnblogs.com/tianzhiliang/articles/2400176.html

 

TIME_WAIT 相關的網絡原理,參見:http://www.cnblogs.com/digdeep/p/4869010.html

 

 

 

 

 

 

================================下面的修改沒有起作用,可忽略=======================================

修改配置,增加 tomcat 的鏈接配置:

1.在 conf目錄下的 server.xml 中 找到 <Connector 元素加入  maxThreads="800" maxConnections="10000" acceptCount="1000" 

1> maxThreads: 表示最大tomcat可以開啟的線程數量,一個線程處理一個請求;

2> maxConneections: 表示最大的socket連接數;

3> acceptCount: 表示當所有的maxThreads的線程都忙於處理時,排隊等待被處理的隊列的長度;

2. 修改dbcp 數據庫(sql server 2005)鏈接配置:

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName">
            <value>${dataSource_driverClassName}</value>
        </property>
        <property name="url">
            <value>${dataSource_url}</value>
        </property>
        <property name="username">
            <value>${dataSource_username}</value>
        </property>
        <property name="password">
            <value>${dataSource_password}</value>
        </property>
        <!--maxActive: 最大連接數量-->    
        <property name="maxActive" value="150"/>  
        <!--minIdle: 最小空閑連接-->    
        <property name="minIdle" value="5"/>  
        <!--maxIdle: 最大空閑連接-->    
        <property name="maxIdle" value="20"/>  
        <!--initialSize: 初始化連接-->    
        <property name="initialSize" value="30"/>  
        <!-- 連接被泄露時是否打印 -->  
        <property name="logAbandoned" value="true"/>  
        <!--removeAbandoned: 是否自動回收超時連接-->    
        <property name="removeAbandoned"  value="true"/>  
        <!--removeAbandonedTimeout: 超時時間(以秒數為單位)-->    
        <property name="removeAbandonedTimeout" value="10"/> 
        <!--maxWait: 超時等待時間以毫秒為單位 1000等於60秒-->  
        <property name="maxWait" value="1000"/>  
        <!-- 在空閑連接回收器線程運行期間休眠的時間值,以毫秒為單位. -->  
        <property name="timeBetweenEvictionRunsMillis" value="10000"/>  
        <!--  在每次空閑連接回收器線程(如果有)運行時檢查的連接數量 -->  
        <property name="numTestsPerEvictionRun" value="10"/>  
        <!-- 1000 * 60 * 30  連接在池中保持空閑而不被空閑連接回收器線程-->  
        <property name="minEvictableIdleTimeMillis" value="10000"/>   
        <property name="validationQuery" value="select 1"/>  
    </bean>

數據庫框架采用的是 ibatis 框架。

原來的 dbcp 只有 最上面的四項配置:

        <property name="driverClassName">
            <value>${dataSource_driverClassName}</value>
        </property>
        <property name="url">
            <value>${dataSource_url}</value>
        </property>
        <property name="username">
            <value>${dataSource_username}</value>
        </property>
        <property name="password">
            <value>${dataSource_password}</value>
        </property>

估計就是這里的配置問題。(注:結果該證明猜測是錯誤的。)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM