Tomcat中的错误“打开的文件太多”

Posted

技术标签:

【中文标题】Tomcat中的错误“打开的文件太多”【英文标题】:Error in tomcat "too many open files" 【发布时间】:2013-11-07 08:04:15 【问题描述】:

我在 tomcat 上运行了一个应用程序,有时会出现以下错误:

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:522)
at java.net.ServerSocket.accept(ServerSocket.java:490)
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:722)

....

SEVERE: Error processed default web.xml named conf/web.xml at /local/myApp/apache-tomcat/conf/web.xml
java.io.FileNotFoundException: /local/myApp/apache-tomcat/conf/web.xml (Too many open files)
        at java.io.FileInputStream.open(Native Method)
        at java.io.FileInputStream.<init>(FileInputStream.java:138)
        at org.apache.catalina.startup.ContextConfig.getWebXmlSource(ContextConfig.java:1838)
        at org.apache.catalina.startup.ContextConfig.getGlobalWebXmlSource(ContextConfig.java:1745)
        at org.apache.catalina.startup.ContextConfig.getDefaultWebXmlFragment(ContextConfig.java:1418)
        at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1253)
        at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:878)
        at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:369)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5269)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3926)
        at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
        at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1345)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1530)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1519)
        at java.lang.Thread.run(Thread.java:722)

我检查了打开文件的限制,它是 1024,但是当我用 lsof 检查应用程序的打开文件数时,它接近 200,如果它没有达到限制,为什么会发生这种情况? 我应该提高限额吗?还有其他原因会出现此错误吗? 让服务再次正常运行的唯一方法是重新启动tomcat,还有其他方法可以恢复正常吗?

提前致谢。

编辑: 这是处理doPost方法的servlet,一开始我没有关闭每个流,可能是这样吗?为此,我添加了 finally 语句:

    InputStream is = null;
    DataInputStream dis = null;
    OutputStream os = null;
    DataOutputStream dos = null;
    String paramName = "";
    try 
        os = response.getOutputStream();
        is = request.getInputStream();
        dis = new DataInputStream(is);
        dos = new DataOutputStream(os);
        .....
        catch (Throwable e) 
        LOGGER.error(e.getMessage());
         finally 
          if (dis != null) 
             dis.close();
           
           else if(is != null) 
             is.close();
                           
           if (dos != null) 
             dos.close();
           
           else if( os != null) 
             os.close();
           
        

EDIT2: 在进行了一些测试之后,我意识到如果我先关闭 DataInputStream 然后再关闭 InputStream,我会在消息之前获得一个数字(我不知道为什么)。我更改了关闭流的顺序,似乎一切正常。但我仍然有问题。有什么想法吗?

  finally 

    if(is != null) 
        try 
            is.close();
         catch (IOException e) 
            LOGGER.error(e.getMessage());
        
    
    if (dis != null) 
        try 
            dis.close();
         catch (IOException e) 
            LOGGER.error(e.getMessage());
        
    
    if(os != null) 
        try 
            os.close();
         catch (IOException e) 
            LOGGER.error(e.getMessage());
        
    
    if (dos != null) 
        try 
            dos.close();
         catch (IOException e) 
            LOGGER.error(e.getMessage());
        
    

【问题讨论】:

是的,我检查了这个网站,但作为服务,它也没有使用超过 200 个作为最大值,为什么要增加到 4096 个限制? 你应该先在网站上搜索你的错误:***.com/questions/5656458/… 分享你的代码!没有任何代码sn-p,我们无能为力。 @developerwjk 首先我检查了网站并增加了打开文件的限制可能是一个想法,但由于我没有达到限制的上限,我认为它不会解决我的问题。跨度> tomcat是运行在Windows还是Linux机器上? 【参考方案1】:

执行以下操作以获取 tomcat7 的 pid,例如 1234

ps aux |grep tomcat7

然后做

cat /proc/1234/limits 读取如下一行

Max open files 16384 16384 files

这是 Tomcat 允许的最大打开文件数。要增加它,请按照以下说明进行操作

Too many open files Tomcat.

【讨论】:

我已经检查并增加打开文件的数量到无法访问的数量。我认为这更像是对应用程序内部线程的不良管理,可能吗? 是的,我猜您可能正在泄漏应用程序中的文件处理程序/连接。 有没有办法查看这些打开文件的列表?并且查看打开它们的线程会很有用。【参考方案2】:

按照以下说明快速分析服务器的当前配置并调整 tomcat 硬限制和软限制以解决此问题。

这将显示该进程的所有打开文件。

ls -l /proc/tomcatPID/fd 

这将显示打开文件的数量。

ls -l /proc/tomcatPID/fd | wc -l 

增加打开文件限制更新/etc/security/limits.conf

检查特定于 tomcat 的打开文件的数量:

硬限制:su - tomcat -c 'ulimit -Hn' -s '/bin/bash'

软限制:su - tomcat -c 'ulimit -Sn' -s '/bin/bash'

您可以使用玉米作业运行以下脚本以了解打开文件的详细信息。

=============================
#!/bin/bash

PID=$(ps -ef|grep tomcat6|grep -v grep |awk 'print $2')
value=$(ls -l /proc/$PID/fd | wc -l)
echo `date`@$PID:$value >> /usr/local/filecount.txt
if [ $value -gt 2000 ];
then
printf "\n\n\n\n\n" >> /usr/local/files_report.txt
echo "-------------------------------`date`--Starting Session----------------------" >> /usr/local/files_report.txt
openfiles=$(ls -l /proc/$PID/fd | awk 'print NR,$11 "" >> "/usr/local/files_report.txt"')
echo "--------------------`date`---Ending  Session ------------------------------" >> /usr/local/files_report.txt
fi
================= 

【讨论】:

格式化好。【参考方案3】:

知道您可以通过将以下内容添加到/etc/security/limits.conf 来更改打开文件的限制可能会很有用:

* soft nofile 2048 # Set the limit according to your needs
* hard nofile 2048

然后您可以在 shell 上使用 sysctl -p 重新加载配置。检查this article。

为了完整起见,您可以使用以下命令验证打开文件的当前限制:ulimit -n

【讨论】:

【参考方案4】:

@gaboroncancio 发布的答案基本上是正确的,但他关于如何使设置生效的建议并不完全正确。 sysctl -p 将重新加载 /etc/sysctl.conf,或者您作为参数传入的任何文件。但是,sysctl 命令将无法识别/etc/security/limits.conf 的格式。

要重新加载/etc/security/limits.conf,您只需注销并重新登录。

【讨论】:

是的值重新加载需要重新登录【参考方案5】:

    如果此代码来自网络操作(套接字),我不确定 Java XxxxxStrem 与操作系统文件限制是否有 1:1 的关系(或根本没有关系)。也许需要一些研究,异常消息有错误的文本?经常出现在软件中。

    我的直觉说,我们不理解异常 2,代码中没有任何内容(或有问题的配置不存在)有关系。

    当软件错误(泄漏)是主要问题时,扩展操作系统文件限制是错误的政策,正如您所理解的那样

【讨论】:

以上是关于Tomcat中的错误“打开的文件太多”的主要内容,如果未能解决你的问题,请参考以下文章

java.net.SocketException:Spring Hibernate Tomcat 打开的文件太多

grails 应用程序中的“打开的文件太多” - 如何正确关闭打开的文件和流?

火花中止火花作业中打开的文件太多

无法打开设备:打开的文件太多错误

错误:EMFILE:打开的文件太多 - React Native CLI

节点和错误:EMFILE,打开的文件太多