【问题标题】:java.net.SocketException: java.net.SocketException: Too many open filesjava.net.SocketException: java.net.SocketException: 打开的文件太多
【发布时间】:2014-12-09 07:03:13
【问题描述】:

我有一个大型 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环境下出现。

【问题讨论】:

  • 您正在泄漏连接,您也不需要继续重新创建DataSource。一个会做的。
  • 您的应用程序部署在哪里?是linux环境吗?
  • @EJP 只有当dmDatasource 为空时,我才会再次创建连接。你能更清楚你想说什么吗?
  • @JavaDev- 不,它在 windows 环境中。
  • 我们根本看不到您在哪里创建或关闭Connections。只有DataSources. 你似乎把他们弄糊涂了。它们不是一回事。

标签: java mysql database socketexception


【解决方案1】:

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

ulimit -a 

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

/etc/security/limits.conf 

例如

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

【讨论】:

  • 只有这个my_username hard maxlogins 10 条目在我的用户名的limits.conf 文件中。我应该再添加两个你上面建议的吗?
【解决方案2】:

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

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

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

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

在 Linux 上,您可以作为 root 用户更改每个进程(通过 ulimit -n)和每个系统(例如 echo 800000 &gt; /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)

【讨论】:

  • “Java 打开许多文件以读取运行应用程序所需的类”是正确的,但它也会立即关闭它们:通常它们也都在 JAR 文件中,这大大减少了负载。基本问题不是连接数,而是存在明显的资源泄漏
  • @EJP 你说得对,类加载器会立即关闭(应该)所有资源。在某些特殊情况下,通常在系统负载较重的情况下,可能会出现第一次访问某个类的原因,这种异常通常不会出现。我还认为您对存在资源泄漏的评估是正确的。但目前我对环境、负载等了解不够,这会导致问题
猜你喜欢
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多