我有一个大的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环境中发生。
答案 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)