9

我们最近发生了一个中断事件,应用程序线程在从 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 获取连接。

在日志中看到的 Stacktrace:

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 文档中提取的一些摘录

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

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

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

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

我的问题如下:

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

谢谢

4

2 回答 2

2

网络分区存在了几分钟。我假设到那时,空闲连接测试将使池中的所有活动连接无效。这意味着 c3p0 现在将参与获取新连接。如果任何应用程序主机尝试从池中获取连接,它必须无限期地等待直到获得连接(参见 c3p0 文档的摘录)。

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

在这种情况下,结帐超时参数也无济于事,因为它仅在所有连接都被签出时才强制超时(事实并非如此)。

  1. 根据 c3p0 文档:此超时在“结帐时”强制执行,而不是在连接已签出时强制执行。所以它应该可以帮助你。

  2. checkoutTimeout可以帮助您处理客户端超时,因此无需实现其他任何东西;但是我会说尝试无限期地获得连接是一个错误。我实际上使用默认的 30 x 1000 ms = 30 秒超时。

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

于 2014-10-30T17:45:12.327 回答
0

根据文档,这就是问题所在。

c3p0.acquireRetryAttempts = 0;

如果 acquireRetryAttempts 为 0,则 C3P0 会不断尝试在失败时获取连接,无限期地迭代,每次迭代等待 10 秒(如您配置的那样)。

将 acquireRetryAttempts 更改为 10 之类的有限值,您的等待将在 100 秒左右,然后出现异常。

于 2021-04-06T15:24:56.970 回答