【问题标题】:Running out of DB connections!数据库连接用完了!
【发布时间】:2011-07-11 06:59:19
【问题描述】:

我正在使用 c3p0 作为连接池运行 Spring/Hibernate 连接到 MySQL 设置。出于某种奇怪的原因,当系统处于负载状态时(当然),它会失去连接。

在我们开始达到新的流量水平(超过一百个并发用户)之前,该网站非常稳定。那时数据库会崩溃(与 CPU 挂钩)。我的第一个动作是在应用程序中通过广泛的缓存和查询优化等来提高性能。

现在它会间歇性地用完连接。它甚至似乎并不依赖于负载。更多的时间让我认为这是一个泄漏,但对于我的生活,我无法弄清楚它会来自哪里。

    WARN [2011-03-07 17:19:42,409] [TP-Processor38] (JDBCExceptionReporter.java:100) - SQL Error: 0, SQLState: null
ERROR [2011-03-07 17:19:42,409] [TP-Processor38] (JDBCExceptionReporter.java:101) - An attempt by a client to checkout a Connection has timed out.
ERROR [2011-03-07 17:19:42,410] [TP-Processor38] (HttpHeadFilter.java:46) - There was a problem passing thru filter:/is-this-guy-crazy-or-just-a-huge-dancing-with-the-stars-fan
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.exception.GenericJDBCException: could not execute query
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:659)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)

Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:527)
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)

这是我的配置:

 <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource" ref="rootDataSource" />
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="mappingLocations" value="classpath:hibernate-mapping.xml" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.connection.provider_class">net.sf.hibernate.connection.C3P0ConnectionProvider</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.generate_statistics">true</prop>
                <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>
                <prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
                <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
                <prop key="hibernate.bytecode.use_reflection_optimizer">${hibernate.bytecode.use_reflection_optimizer}</prop>
                <!--<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>-->
                <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>

                <!--Actually, it seems the following property affects batch size (or explicit per relationship in the mapping)-->
                <!--<prop key="hibernate.default_batch_fetch_size">${hibernate.jdbc.batch_size}</prop>-->
            </props>
        </property>
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="rootDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="initialPoolSize" value="20" />
        <property name="maxPoolSize" value="200" />
        <property name="checkoutTimeout" value="30000" />
        <property name="maxStatements" value="180" />

        <property name="minPoolSize">
            <value>${hibernate.c3p0.minPoolSize}</value>
        </property>
        <property name="acquireRetryAttempts">
            <value>${hibernate.c3p0.acquireRetryAttempts}</value>
        </property>
        <property name="acquireIncrement">
            <value>${hibernate.c3p0.acquireIncrement}</value>
        </property>
        <property name="idleConnectionTestPeriod">
            <value>${hibernate.c3p0.idleConnectionTestPeriod}</value>
        </property>
        <property name="maxIdleTime">
            <value>${hibernate.c3p0.maxIdleTime}</value>
        </property>
        <property name="maxIdleTimeExcessConnections">
            <value>${hibernate.c3p0.maxIdleTimeExcessConnections}</value>
        </property>
        <property name="maxConnectionAge">
            <value>${hibernate.c3p0.maxConnectionAge}</value>
        </property>
        <property name="preferredTestQuery">
            <value>${hibernate.c3p0.preferredTestQuery}</value>
        </property>
        <property name="testConnectionOnCheckin">
            <value>${hibernate.c3p0.testConnectionOnCheckin}</value>
        </property>
        <property name="numHelperThreads">
            <value>${hibernate.c3p0.numHelperThreads}</value>
        </property>
        <property name="unreturnedConnectionTimeout">
            <value>${hibernate.c3p0.unreturnedConnectionTimeout}</value>
        </property>
        <property name="debugUnreturnedConnectionStackTraces">
            <value>${hibernate.c3p0.debugUnreturnedConnectionStackTraces}</value>
        </property>
        <property name="automaticTestTable">
            <value>${hibernate.c3p0.automaticTestTable}</value>
        </property>
    </bean>
    hibernate.c3p0.acquireIncrement=5
hibernate.c3p0.minPoolSize=20
hibernate.c3p0.acquireRetryAttempts=30
hibernate.c3p0.idleConnectionTestPeriod=3600
hibernate.c3p0.maxIdleTime=7200
hibernate.c3p0.maxIdleTimeExcessConnections=1800    
hibernate.c3p0.maxConnectionAge=14400
hibernate.c3p0.preferredTestQuery=select 1;
hibernate.c3p0.testConnectionOnCheckin=false
hibernate.c3p0.numHelperThreads=6
hibernate.c3p0.unreturnedConnectionTimeout=0
hibernate.c3p0.debugUnreturnedConnectionStackTraces=true
hibernate.c3p0.automaticTestTable=test_connection;

我正在运行应该关闭连接的 OpenSessionInViewInterceptor:

 <bean id="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    <property name="sessionFactory">
        <ref bean="sessionFactory" />
    </property>
    <property name="flushModeName">
        <value>FLUSH_AUTO</value>
    </property>

</bean>

我还在为 @Transactional 使用 spring 注释,因为我在非 Web 前端代码中重用了我的服务。

这里实际上只有两个选项,完成后不会释放连接。或者它正在和数据库聊天,就像它试图穿上她的裤子一样。 如果有人有任何想法,我将不胜感激 谢谢

跟进: 最后,我发现由于使用 OpenSessionInViewInterceptor 导致连接泄漏。我将spring security作为过滤器运行,因此它可以连接到数据库并且永​​远不会关闭它们。解决方法是将 OpenSessionInViewInterceptor 移动到 OpenSessionInViewFilter。

【问题讨论】:

    标签: hibernate spring connection c3p0 pooling


    【解决方案1】:

    我也遇到了这个问题,我通过将 C3P0 的 checkoutTimeout 属性设置为 0 而不是大于 0 的值来解决。

    事实上,我有很多线程在等待连接,10 秒后,出现了和你一样的错误。

    在此处查看文档:http://www.mchange.com/projects/c3p0/#checkoutTimeout

    【讨论】:

      【解决方案2】:

      我也有这个问题。原因是用户没有对主机的授权,因为 /etc/hosts 条目已被修改。

      【讨论】:

        【解决方案3】:

        无论您对 C3P0 进行何种配置(通过休眠),您都可能受到 MySQL 本身的限制。请记住,默认情况下 MySQL 允许的最大连接数是 100!因此,即使您告诉 C3P0 最多汇集 200、500 或 1000 个连接,这也是无法实现的。使用以下命令打开 MySQL shell:

        $ msql -u [user] -p
        

        然后键入以下内容以获得允许的最大连接数:

        $ show variables where Variable_name='max_connections';
        

        如果返回的数字对于您的应用程序来说太低,请考虑更改它(编辑您的 my.cnf 文件,通常位于 Linux 系统上的 /etc/mysql/ 中)。

        【讨论】:

          【解决方案4】:

          尝试启用日志记录并将c3p0.debugUnreturnedConnectionStackTraces 属性设置为true。还将c3p0.unreturnedConnectionTimeout 设置为小于平均查询时间(1 秒?)。然后任何花费超过超时时间的事情都会记录堆栈跟踪。这应该可以让您快速缩小范围。

          如果堆栈跟踪没有模式,可能只是您的池太小。你说有 100 个并发用户,但你知道这是每秒多少个查询吗?如果它是每秒 100 次查询并且您有 20 个连接,那么每个 sql 执行需要花费不到 200 毫秒(20 个连接 => 每秒 20 秒的总工作时间来执行 100 次查询)。

          【讨论】:

            【解决方案5】:

            @Transactional 泄漏连接的可能性很小 - 否则,您的网站将在前 100 个请求后停止工作。

            但发生这种情况还有另一个原因:

            也许您已经为“死”连接设置了超时时间,而某些查询需要的时间比这更长。这意味着您的池将一个繁忙的连接作为“死”从池中移除,并从数据库请求另一个 - 直到数据库拔掉插头。

            要对此进行调试,请为您的连接池启用日志记录,以便您可以看到它何时请求新连接。

            【讨论】:

            • 我的 maxConnectionAge 设置为 14400,根据文档,它以秒(而不是毫秒)为单位,因此是 240 分钟。我肯定会尝试打开日志记录。问题是它打开和关闭了大量的连接,因此很难隔离它发生的位置。尤其是在负载下。
            猜你喜欢
            • 2012-07-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多