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)的限制。
相关文章
相关标签/搜索