Tomcat報異常:Too many open files 的解決之路

Tomcat報 Jul 21, 2015 8:45:23 AM org.apache.tomcat.util.net.JIoEndpoint$Acceptor runSEVERE: Socket accept failedjava.net.SocketException: Too many open filesat java.net.PlainSocketImpl.socketAccept(Native Method)at java.net.AbstractPlainSocjava

Tomcat報
Jul 21, 2015 8:45:23 AM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run
SEVERE: Socket accept failed
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.ServerSocket.implAccept(ServerSocket.java:530)
at java.net.ServerSocket.accept(ServerSocket.java:498)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)
at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:216)
at java.lang.Thread.run(Thread.java:745)
解決的思路:
一眼異常馬上想到ulimit,因而使用
ulimit -a
 查看Linux內核容許的最大資源
open files (-n) 1024
須要調大限制
ulimit -n 65535
通過觀察,問題依舊...

經過
lsof|grep tomcat|wc -l
看到tomcat的io竟然有1082個,立馬想到了nginx與tomcat的不協調形成的,據網絡資料顯示:tomcat端默認開啓了 keepalive,而nginx把鏈接交給了tomcat並不關係是否關閉,所以tomcat須要等待"connectionTimeout"設置的超 時時間來關閉,因此最好設置「maxKeepAliveRequests」爲1,讓每一個鏈接只相應一次就關閉,這樣就不會等待timeout了。所以設置 tomcat:
<Connector port="8080" protocol="HTTP/1.1"
                maxKeepAliveRequests="1"
              connectionTimeout="20000"
              URIEncoding="UTF-8"
              redirectPort="8443" />
   <!-- A "Connector" using the shared thread pool-->
   <!--
   <Connector executor="tomcatThreadPool"
              port="8080" protocol="HTTP/1.1"
               maxKeepAliveRequests="1"
              connectionTimeout="20000"
              redirectPort="8443" />
重啓tomcat,觀察,問題依舊!

翻頁查看lsof
lsof|grep tomcat|more

發現有大量的memcached的IO,所以把問題定位在memcached上,爲了方便觀察,新建memcached實例,發現memcached的IO數量逐步增長,最終致使tomcat崩潰!
嗨,終於找到問題了 ^O^

經過code review,發現每次調用memcached的API,都會new一個XMemcachedClient(一個memcached客戶端),每次new的時候都會設置一個尺寸的鏈接池,而鏈接是預創建的,所以致使memcached的IO數目劇增。

問題終於解決了,memcached的IO數目穩定了,tomcat也運行良好。。。

不經意間,發現memcached的IO數目以鏈接池的尺寸在遞增,內心一落千丈,拔涼拔涼的,貌似仍是沒解決!

查看tomcat的日誌,發現了端倪:
Jul 21, 2015 3:06:40 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MobileService] appears to have started a thread named [Xmemcached-Reactor-0] but has failed to stop it. This is very likely to create a memory leak.
原來在每次從新部署webapp時,tomcat殺不掉XmemcachedClient的鏈接進程,因爲使用的是spring,因此須要在memcachedClient的bean裏增長"destroy-method"。
OK,到此爲止tomcat的IO以及memcached的IO都穩定了,並在合理範圍以內,tomcat的是160左右。
爲了擔憂「maxKeepAliveRequests」的設置對tomcat的性能有影響,暫時刪除了「 maxKeepAliveRequests」,須要對tomcat的總體性能優化進行了解纔去配置。
小插曲:因爲使用了spring框架的監聽配置Log4j,若是下面的順序顛倒了會形成不能寫日誌的問題
<listener>
	<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
通過一天的推理、懷疑、實驗、否認,終於搞定,又過了一次"福爾摩斯"的偵探癮,做此標記,留給後來人!

今天發現打開的IO仍然在增長,雖然幅度比較少,但最高也達到了960+,所以須要優化Tomcat配置,增長線程池,並配置keepAliveTimeout和maxKeepAliveRequests
<Executor name="mobileThreadPool" namePrefix="catalina-exec-"
maxThreads="600" minSpareThreads="20" maxIdleTime="60000" />
 
<Connector executor="mobileThreadPool" port="8080" protocol="HTTP/1.1"
	connectionTimeout="20000"
	keepAliveTimeout="15000"
	maxKeepAliveRequests="1"
	URIEncoding="UTF-8"
	redirectPort="8443" />

今天使用壓力測試,依然出現「Too many open files」,使用ulimit發現「open files (-n)」仍然是1024,那麼以前設置的65535是沒起做用,而切換到root用戶發現倒是65535;而在非root用戶下
ulimit -n 65535
會報異常:
ulimit: max user processes: cannot modify limit
原來是被 /etc/security/limits.conf 限制了,打開此文件便可看到,對默認用戶是有限制的,所以能夠加入
*        soft    noproc 65535
*        hard    noproc 65535
*        soft    nofile 65535
*        hard    nofile 65535
 

這樣就非root用戶就能夠設置ulimit爲65535了。nginx

設置了ulimit後,我在root下啓動tomcat,壓力還會容易出現「Too many open files」,但其實使用「lsof -u root|wc -l」並很少,才3000+;root後來我單獨創建了個用戶來啓動,暫時沒出現問題。web

PS:spring

/proc/sys/fs/file-max表示kernel中維護的最大文件描述符數目。無論這個系統上有多少了用戶登陸,有多少個進程在運行,全部打開的文件數目總合都不能超過這個數字。shell

/etc/security/limit.conf用來設置每一個用戶最多能夠打開的文件數目。apache

普通用戶能夠經過ulimit -n 命令來設置hard limit(只能改小) 和soft limit(能夠改大和改小).tomcat

把上面的內容歸納成3條就是:性能優化

  1. /proc/sys/fs/file-max 控制整個系統。
  2. /etc/security/limit.conf控制每一個用戶, 且受到(1)的限制。
  3. ulimit -n用來控制shell及其子進程, 且受到(2)的限制。
相關文章
相關標籤/搜索