最近系統二次開發以後,發現使用的 Tomcat 7 會常常假死。前端點擊頁面無任何反應,打開firebug,不少連接一直在等待服務器的反應。查看服務器的狀態,CPU佔用不多,最多不超過10%,通常只有2%,3%左右,內存佔用卻是接近80, 90%。一開始懷疑是tomcat內存配置不夠,可是打開 jvisualvm.exe 分析,發現Tomcat 佔用的堆內存沒有什麼問題。由於是假死,因此最後懷疑到 tomcat的 連接數和 數據庫的連接數的配置估計過小了。netstat -na 結果頁顯示不少time_wait.html
查看各類狀態的網絡鏈接的數量:前端
1)Linux 使用命令:netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'nginx
上面的命令能夠查出各類狀態的網絡鏈接的數量
2)windows使用命令:sql
netstat -n |find /i "time_wait" /c數據庫
netstat -n |find /i "close_wait" /capache
netstat -n |find /i "established" /cwindows
windows下沒有awk,因此要一個一個狀態的統計它們的數量。tomcat
結果是:服務器
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>
估計就是這裏的配置問題。(注:結果該證實猜想是錯誤的。)