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 からの接続を取得しようとして無期限にスタックしていることがわかりました。

ログに表示されるスタック トレース:

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 の遅延があります。すべての試行が失敗した場合、DataSource からの接続を待機しているすべてのクライアントに例外が表示され、接続を取得できなかったことを示します。クライアントは、試行の完全なラウンドが失敗するまで例外を認識しないことに注意してください。これは、最初の接続試行からしばらく時間が経過する可能性があります。acquireRetryAttempts が 0 に設定されている場合、c3p0 は新しい Connections の取得を無期限に試行し、getConnection() の呼び出しは取得の成功を待って無期限にブロックされる可能性があります

checkoutTimeout は、すべての Connection がチェックアウトされ、1 つをすぐに提供できない場合に、クライアントが Connection を待機する時間を制限します。

だから、これがなぜ起こったのかについての私の理論は次のとおりです。

ネットワークの分割は数分間存在しました。それまでに、アイドル接続テストにより、プール内のすべてのアクティブな接続が無効になっていると思います。これは、c3p0 が新しい接続の取得に関与することを意味します。アプリケーション ホストがプールから接続を取得しようとすると、接続が取得されるまで無期限に待機する必要があります (c3p0 ドキュメントからの抜粋を参照)。また、チェックアウト タイムアウト パラメータは、すべての接続がチェックアウトされた場合にのみタイムアウトを適用するため、この場合には役に立ちませんでした (実際にはそうではありませんでした)。

ここでの私の質問は次のとおりです。

  1. システムに関する私の理解は正しいですか?
  2. はいの場合、永遠にハングアップするのではなく、そのようなアプリケーション接続要求をタイムアウトにする checkoutTimeout (または他のパラメーターが存在する) べきですか?
  3. この問題に再び直面しないように c3p0 を構成するより良い方法があれば。タイムアウト (スレッドベースのタイムアウト) を強制する c3p0 から接続を取得するラップを試すことができますが、より良い c3p0 構成を持つか、c3p0 パッチを適用することが可能であれば、これは避けたいものです。

ありがとう

4

2 に答える 2

2

ネットワークの分割は数分間存在しました。それまでに、アイドル接続テストにより、プール内のすべてのアクティブな接続が無効になっていると思います。これは、c3p0 が新しい接続の取得に関与することを意味します。アプリケーション ホストがプールから接続を取得しようとすると、接続が取得されるまで無期限に待機する必要があります (c3p0 ドキュメントからの抜粋を参照)。

  1. これは正しくありません。checkoutTimeoutは、このシナリオだけでなく、システムが過負荷になっている場合 (プールが上限に達し、すべての接続が使用されている場合) も制御する必要があります。

また、チェックアウト タイムアウト パラメータは、すべての接続がチェックアウトされた場合にのみタイムアウトを適用するため、この場合には役に立ちませんでした (そうではありませんでした)。

  1. c3p0 のドキュメントによると、このタイムアウトは、接続が既にチェックアウトされているときではなく、「チェックアウト時」に適用されます。だからそれはあなたを助けるはずです。

  2. checkoutTimeoutは、クライアントのタイムアウトを支援するために存在するため、他に何も実装する必要はありません。ただし、無期限に接続を取得しようとするのは間違いだと思います。私は実際にはデフォルトの 30 x 1000 ミリ秒 = 30 秒のタイムアウトを使用しています。

また、checkoutTimeout は aquire タイムアウト (acquireRetryAttempts * acquireRetryDelay) よりも大きいか等しい必要があると言えます。それ以外の場合は、2 番目が適用されます。

于 2014-10-30T17:45:12.327 に答える