Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 569|回复: 0

Tomcat报异常:Too many open files 的解决之路

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-18 14:09:37 | 显示全部楼层 |阅读模式

    http://www.linuxeye.com/Linux/2781.html

    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.AbstractPlainSoc

    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了。

    设置了ulimit后,我在root下启动tomcat,压力还会容易出现“Too many open files”,但其实使用“lsof -u root|wc -l”并不多,才3000+;root后来我单独建立了个用户来启动,暂时没出现问题。

    PS:

    /proc/sys/fs/file-max表示kernel中维护的最大文件描述符数目。不管这个系统上有多少了用户登录,有多少个进程在运行,所有打开的文件数目总合都不能超过这个数字。

    /etc/security/limit.conf用来设置每个用户最多可以打开的文件数目。

    普通用户可以通过ulimit -n 命令来设置hard limit(只能改小) 和soft limit(可以改大和改小).

    把上面的内容概括成3条就是:

    1. /proc/sys/fs/file-max 控制整个系统。
    2. /etc/security/limit.conf控制每个用户, 且受到(1)的限制。
    3. ulimit -n用来控制shell及其子进程, 且受到(2)的限制。

    转载请保留固定链接: http://www.linuxeye.com/Linux/2781.html

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-3 06:55 , Processed in 0.062790 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表