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

时间:2014-12-09 07:03:14

标签: java mysql database socketexception

我有一个大的java应用程序(用于生成某种类型的报告),其中使用下面的类来创建数据源。

 import org.apache.log4j.Logger;
 import org.springframework.jdbc.datasource.DriverManagerDataSource;
 import com.mysql.jdbc.Connection;
 public class DatabaseConnection
  {
     private static final Logger LOGGER = Logger.getLogger(DatabaseConnection.class.getName());
    @SuppressWarnings("deprecation")
    public static DriverManagerDataSource jdbcConnection(WebmartConfiguration webmartconnection)
    {
        DriverManagerDataSource dataSource = null;
        try
        {
            dataSource = new DriverManagerDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://" + webmartconnection.getHostname() + ":" + webmartconnection.getPort() + "/" + webmartconnection.getDatabasename() + "", webmartconnection.getUsername(), webmartconnection.getPassword());
    }
    catch (Exception sqle)
    {
        LOGGER.info(sqle);
    }
    return dataSource;
 }
}

并且该数据源被传递给许多用于使用JDBCTEMPLATE的查询方法执行查询的方法。有一段时间,应用程序运行平稳并生成报告,但在一段时间后,应用程序终止并跟随堆栈跟踪。

ERROR [run has started] (DivisionThread.java:217) - Could not get JDBC Connection;      nested exception is com.mysql.jdbc.CommunicationsException:     Communications link failure due to underlying exception:    

** BEGIN NESTED EXCEPTION **    

java.net.SocketException    
MESSAGE: java.net.SocketException: Too many open files  

STACKTRACE: 

java.net.SocketException: java.net.SocketException: Too many open files 
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:156)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:276)
at com.mysql.jdbc.Connection.createNewIO(Connection.java:2641)
at com.mysql.jdbc.Connection.<init>(Connection.java:1531)
   at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:266)
   at java.sql.DriverManager.getConnection(DriverManager.java:579)
   at java.sql.DriverManager.getConnection(DriverManager.java:190)
   at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:173)
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:164)
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnectionFromDriver(AbstractDriverBasedDataSource.java:149)
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnection(AbstractDriverBasedDataSource.java:119)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:729)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:745)
at com.mpsinsight.reporting.dao.common.CommonUtilReport.getOutFileName(CommonUtilReport.java:1509)
at com.mpsinsight.reporting.bean.common.ActionEnum$9.getparameterType(ActionEnum.java:507)
at com.mpsinsight.reporting.main.common.JasperReport.populateParameters(JasperReport.java:142)
at com.mpsinsight.reporting.main.common.JasperReport.generateReport(JasperReport.java:61)
at com.mpsinsight.reporting.main.common.GenerateReport$4.generateReport(GenerateReport.java:123)
at com.mpsinsight.reporting.main.common.DivisionThread.run(DivisionThread.java:179)


** END NESTED EXCEPTION **  

示例: 下面是使用数据源的应用程序之一。

public String getOutFileName(DriverManagerDataSource datasource, WebmartConfiguration     webmartconnection, String abbrev)
    {
    DriverManagerDataSource dmDatasource = null;
    dmDatasource = datasource;
    if (dmDatasource == null)
    {
        dmDatasource = DatabaseConnection.jdbcConnection(webmartconnection);
    }
    JdbcTemplate jdbcTemplateOb = new JdbcTemplate(dmDatasource);
    String sql = QueryList.Value("outFileNameQuery");

    LOGGER.info("abbrev :::: " + abbrev);
    LOGGER.info("outFileNameQuery :::: " + sql);

    String pathname = (String) jdbcTemplateOb.queryForObject(sql, new Object[] { abbrev }, String.class);

    LOGGER.info("pathname :::: " + pathname);
    return pathname;
}

有人可以解释too many open files错误的原因是什么,以及如何解决它。

编辑: 我正在研究linux环境。上述错误仅在linux环境中发生。

2 个答案:

答案 0 :(得分:1)

使用以下linux命令检查打开文件限制。

ulimit -a 

您可以通过root用户在下面的文件中提供打开文件限制。

/etc/security/limits.conf 

例如

{username}       soft       nofile   1024
{username}       hard   nofile        65536

答案 1 :(得分:1)

“打开文件太多”的原因是应用程序或系统达到了允许的文件句柄的限制。

此问题通常发生在多个并发用户获得与服务器的连接之后。 Java会打开许多​​文件,以便读入运行应用程序所需的类。大批量应用程序可以使用大量文件描述符。这可能导致缺少新的文件描述符。此外,每个新套接字都需要一个描述符。客户端和服务器通过TCP套接字进行通信。当与服务器建立连接时,每个浏览器的http请求都会使用TCP套接字。

为了防止文件描述符泄漏,您应该确保所有资源(如流,数据库连接)一旦不再需要就 explicitly closed 。甚至Java也为您管理资源:不要依赖垃圾收集器来清理您使用过的资源。即,在 finally 块中关闭所有流,或使用Java 7 try with resources语法。

限制的原因是操作系统需要内存来管理每个打开的文件,而内存是有限的资源。不同平台对一次可在单个进程中打开的文件数有不同的限制。

在Linux上,您可以以root用户身份更改每个进程(通过ulimit -n)和每个系统(例如echo 800000 > /proc/sys/fs/file-max)或每个用户的打开文件数的最大值 使用/etc/security/limits.conf文件。对于最后一个选项,您可能需要一个运行应用程序的特殊用户。

在更改这些值中的一个或多个之前,应通过监视打开的文件来检查应用程序是否存在资源泄漏。 Linux上的一个可能选择是使用 strace

strace -e trace=open,close,read,write,connect,accept your-command-here

如果进程可以打印到stderr,则需要使用-o选项将strace的输出放在控制台以外的其他位置。如果您的流程分叉,您还需要-f或-ff

或者,如果您想要将您连接到正在运行的流程,并且您知道流程ID,则可以使用strace -p $MyProcess

如果您在网上搜索,您将找到一个用于监控符合您需求的打开文件描述符的解决方案。例如monitor open process files on linux (real-time)