c3p0 - 应用程序卡在从 c3p0 检索连接上?

标签 c3p0

我们最近发生了一次中断事件,应用程序线程在从 c3p0 检索连接时被卡住。配置集如下:

使用的c3p0版本:0.9.1.2

  • c3p0.acquireRetryDelay = 10000;
  • c3p0.acquireRetryAttempts = 0;
  • c3p0.breakAfterAcquireFailure = false;
  • c3p0.numHelperThreads = 8;
  • c3p0.idleConnectionTestPeriod = 3;
  • c3p0.preferredTestQuery = "从对偶中选择 1";
  • c3p0.checkoutTimeout = 3000;
  • c3p0.user = "XYZ";//发布时更改为 XYZ
  • c3p0.password = "XYZ";//发布时更改为 XYZ

在正常情况下,一切正常,c3p0 一直为我们提供良好的服务。然而,在最近的一次网络事件(网络分区 - 应用程序主机无法与数据库通信)期间,我们发现应用程序无限期地陷入尝试从 c3p0 获取连接的状态。

日志中看到的堆栈跟踪:

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)
    at amazon.identity.connection.WrappedDataSource.getConnectionWithOptionalCredentials(WrappedDataSource.java:42)
    at amazon.identity.connection.LoggingDataSource.getConnectionWithOptionalCredentials(LoggingDataSource.java:55)
    at amazon.identity.connection.WrappedDataSource.getConnection(WrappedDataSource.java:30)
    at amazon.identity.connection.WrappedDataSource.getConnectionWithOptionalCredentials(WrappedDataSource.java:42)
    at amazon.identity.connection.ConnectionProfilingDataSource.profileGetConnectionWithOptionalCredentials(ConnectionProfilingDataSource.java:118)
    at amazon.identity.connection.ConnectionProfilingDataSource.getConnectionWithOptionalCredentials(ConnectionProfilingDataSource.java:99)
    at amazon.identity.connection.WrappedDataSource.getConnection(WrappedDataSource.java:30)
    at amazon.identity.connection.CallCountTrackingDataSource.getConnectionWithOptionalCredentials(CallCountTrackingDataSource.java:82)
    at amazon.identity.connection.WrappedDataSource.getConnection(WrappedDataSource.java:30)
    at com.amazon.jdbc.FailoverDataSource.doGetConnection(FailoverDataSource.java:133)
    at com.amazon.jdbc.FailoverDataSource.getConnection(FailoverDataSource.java:109)
    at com.amazon.identity.accessmanager.WrappedConnection$1.call(WrappedConnection.java:84)
    at com.amazon.identity.accessmanager.WrappedConnection$1.call(WrappedConnection.java:82)
    at com.amazon.identity.accessmanager.WrappedConnection.getConnection(WrappedConnection.java:110)
    ... 40 more
    Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@185e5c6b -- timeout at
 awaitAvailable()
    at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1317)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:584)
....... (total of 317 such instances of prelimCheckoutResource):

我从 c3p0 documentation 中提取的一些摘录

当 c3p0 数据源尝试获取连接但失败时,它将重试最多 acquireRetryAttempts 次,每次尝试之间会延迟 acquireRetryDelay。如果所有尝试都失败,任何等待来自数据源的连接的客户端都会看到异常,表明无法获取连接。请注意,在整轮尝试失败之前,客户端不会看到任何异常,这可能是在初始连接尝试之后的一段时间。 如果 acquireRetryAttempts 设置为 0,c3p0 将无限期地尝试获取新连接,并且对 getConnection() 的调用可能会无限期地阻塞,等待成功获取

checkoutTimeout 限制客户端等待连接的时间,如果所有连接都已 checkout 并且无法立即提供连接

所以这是我关于为什么会发生这种情况的理论:

网络分区存在了几分钟。我假设到那时,空闲连接测试将使池中的所有事件连接无效。这意味着 c3p0 现在将参与获取新连接。如果任何应用程序主机尝试从池中获取连接,则它必须无限期地等待,直到获取连接(请参阅 c3p0 文档的摘录)。此外, checkout 超时参数在这种情况下也无济于事,因为只有在 checkout 所有连接时它才会强制超时(但情况并非如此)。

我的问题如下:

  1. 我对系统的理解正确吗?
  2. 如果是,是否应该 checkoutTimeout (或存在其他一些参数)以使此类应用程序连接请求超时而不是永远挂起?
  3. 是否有更好的方法来配置 c3p0 以避免再次遇到此问题。我可以尝试包装从 c3p0 获取连接,强制超时(基于线程的超时),但如果可能有更好的 c3p0 配置或应用 c3p0 补丁,这是我想避免的事情。

谢谢

最佳答案

The network partitioning existed for several minutes. I am assuming by then, the idle connection tests would have invalidated all active connections in the pool. This means that c3p0 would now be involved in getting new connections. If any application hosts tries to obtain connection from pool, it would have to wait indefinitely until connection has been acquired (see excerpt from the c3p0 docs).

  1. 这是不正确的。 checkoutTimeout 应该控制这种情况以及系统过载时的情况(池已达到最大并且使用了所有连接)。

Also checkout timeout parameter would not have helped in this case since it enforces timeout only if all connections were checked out (and this was not the case).

  • 根据 c3p0 文档:此超时是在“ checkout 时”强制执行的,而不是在连接已 checkout 时强制执行。所以它应该对你有帮助。

  • checkoutTimeout 可以帮助您解决客户端超时问题,因此无需实现其他任何内容;但是我想说,试图无限期地获得连接是一个错误。我实际上使用的是默认的 30 x 1000 毫秒 = 30 秒超时。

  • 我还想说 checkoutTimeout 应该大于或等于获取超时 (acquireRetryAttempts * acquireRetryDelay),否则第二个将适用。

    关于c3p0 - 应用程序卡在从 c3p0 检索连接上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18885903/

    相关文章:

    c3p0 - c3p0 的 JdbcProxyGenerator 如何工作(Java 中的元编程‽)?

    java - 在使用c3p0连接池配置的Mysql主从复制中偶尔会遇到到slave的通信链路故障

    java - 使用 C3P0 时的 JDBC SQLite ATTACH 查询

    java - 查询C3P0启动时获取的连接数

    java - JDBC连接池到同一台服务器上的多个MySQL数据库(使用相同的用户和密码)

    java - 如何在 Java EE 上使用 Hibernate、C3P0 处理数据库连接失败?

    java - C3P0 线程安全吗?

    mysql - Spring Data JPA 和 MySQL : How to avoid "duplicate entry" error in multithreaded environment?

    java - 延迟集合初始化后 Hibernate 连接不会释放

    java - 结果集对象已关闭 - jtds