c3p0连接池拿不到连接导致系统崩溃的问题解决

时间:2024-05-20 20:09:31

问题描述

在一个很突然的时刻,某一台应用服务器挂掉了。该台服务器承载的是一个单体应用,并发量也很小,下面开始排查…

查看服务器进程

①通常在linux服务器上我们查看进程使用的是ps -ef | grep tomcat(使用tomcat作为应用服务器)
②同样也可以使用 jps -l 命令查看当期正在运行的java进程c3p0连接池拿不到连接导致系统崩溃的问题解决

tomcat输出日志查看

我们看到进程是正常的,接下来查看日志输出情况
进入到tomcat/logs目录下
输入命令 tail -f catalina.out查看当前是否有日志输出

java.io.IOException:打开的文件过多
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.(UNIXProcess.java:54)
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.(UNIXProcess.java:54)
at java.lang.Runtime.execInternal(Native Method)
at java.lang.Runtime.exec(Runtime.java:551)
at java.lang.Runtime.exec(Runtime.java:477)
at java.lang.Runtime.exec(Runtime.java:443)

查看当前打开文件大小

lsof -p 直接查看打开的文件
lsof -p | wc -l 查看打开文件的数量 (65560)

然后我们可以查看一下当前服务器支持的最大文件打开数量:
ulimit -a
c3p0连接池拿不到连接导致系统崩溃的问题解决
这里好像已经没有设置最大打开文件数量的空间了

日志分析

我们将服务器的运行日志拷贝到本地,截取服务器挂掉的那个时间段,进行一波日志查看
c3p0连接池拿不到连接导致系统崩溃的问题解决
这里显示这个web应用的实例已经停止,为了调试以及试图终止导致非法访问的线程,将引发以下堆栈跟踪。
通过C3P0PooledConnectionPoolManager[identityToken->10q1nwma11dqw4ut1ya84pd|3384a844, dataSourceName->oracle]-HelperThread-#2这条信息,假象是c3p0连接池出了问题,拿不到连接导致应用停止。

查看c3p0配置信息

c3p0连接池拿不到连接导致系统崩溃的问题解决
到这里仍然没有问题,那会不会是工具类的问题呢?

jdbcutils工具类查看

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

public class JdbcUtils {
    private static  Properties properties = null;
       
    public static Connection getOConnection() {
        //通过标识名来创建相应连接池
        ComboPooledDataSource dataSource = new ComboPooledDataSource("oracle");
        /*Connection con = dataSource.getConnection();

        return  con;*/
        try {
            return dataSource.getConnection();

        } catch (Exception e) {
           // logger.error("Exception in C3p0Utils!", e);
            throw new RuntimeException("数据库连接出错!", e);
        }
    }

    //释放连接回连接池
    public static void close(Connection conn, PreparedStatement pst, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                //logger.error("Exception in C3p0Utils!", e);
                throw new RuntimeException("数据库连接关闭出错!", e);
            }
        }
        if(pst!=null){
            try {
                pst.close();
            } catch (SQLException e) {
                //logger.error("Exception in C3p0Utils!", e);
                throw new RuntimeException("数据库连接关闭出错!", e);
            }
        }

        if(conn!=null && conn.isClosed()){
            try {
                conn.close();
            } catch (SQLException e) {
               // logger.error("Exception in C3p0Utils!", e);
                throw new RuntimeException("数据库连接关闭出错!", e);
            }
        }
    }
}

到这里问题应该是一目了然了。。。
由于每次从c3p0连接池获取连接的时候都会初始化一个dataSource来占用连接池中的一条连接,并且在调用conn.close()之后,只会释放,并不会关闭,所以理论上在调用几次之后,连接池应该已经干涸了。。。

我们将这段代码放到全局中,只要一加载工具类,就初始化一个dataSource就好了
ComboPooledDataSource dataSource = new ComboPooledDataSource(“oracle”);

总结

这个时候一定要会甩锅。。。这个代码不是我写的!!!
然后下次一定不能犯这么蠢的问题。