24

dbcp から tomcat jdbc 接続プールに移行しました。システムをロードして試してみたところ、次の例外が発生しました。

java.sql.SQLException: [IA1856] Timeout: Pool empty. Unable to fetch a connection in 1 seconds, none available[size:125; busy:90; idle:0; lastwait:1000].
        at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:632)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:174)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:124)
        at com.inneractive.model.mappings.BasicPersistenceEntityMapping.getConnection(BasicPersistenceEntityMapping.java:233)
        at com.inneractive.model.mappings.BasicPersistenceEntityMapping.callWithConnection(BasicPersistenceEntityMapping.java:243)
        at com.inneractive.model.mappings.PersistenceEntityMapping.get(PersistenceEntityMapping.java:194)
        at com.inneractive.model.data.client.ClientUtils.GetClientByExamples(ClientUtils.java:353)
        at com.inneractive.client.ExternalAdRingsClientStart.getClientInfoByRequestParametersOrInsert(ExternalAdRingsClientStart.java:1329)
        at com.inneractive.client.ExternalAdRingsClientStart.newClientSession(ExternalAdRingsClientStart.java:245)
        at com.inneractive.simpleM2M.web.SimpleM2MProtocolBean.generateCampaign(SimpleM2MProtocolBean.java:235)
        at com.inneractive.simpleM2M.web.SimpleM2MProtocolBean.generateCampaign(SimpleM2MProtocolBean.java:219)
        at com.inneractive.simpleM2M.web.AdsServlet.doGet(AdsServlet.java:175)
        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.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:555)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:396)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

これに注意してください:

[size:125; busy:90; idle:0; lastwait:1000]

ビジーでない接続はどこにありますか? この後も通話中の番号は下がり続けましたが、それでも接続を確立することはできませんでした.

何か案は?

構成:

<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"
                factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" loginTimeout="10000"
                maxActive="35" maxIdle="35" maxWait="1000" name="jdbc/mysql"
                password="-----" testOnBorrow="true" testOnReturn="false" type="javax.sql.DataSource"
                url="jdbc:mysql://localhost:3306/my_db?elideSetAutoCommits=true&amp;useDynamicCharsetInfo=false&amp;rewriteBatchedStatements=true&amp;useLocalSessionState=true&amp;useLocalTransactionState=true&amp;alwaysSendSetIsolation=false&amp;cacheServerConfiguration=true&amp;noAccessToProcedureBodies=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"
                username="root" validationQuery="SELECT 1"/>

env: ubuntu と tomcat 6.db - mysql

4

3 に答える 3

18

ConnectionPool.javaのソースを見ると、borrowConnection()メソッドで次のコード スニペットにヒットしているようです。

        //we didn't get a connection, lets see if we timed out
        if (con == null) {
            if ((System.currentTimeMillis() - now) >= maxWait) {
                throw new SQLException("[" + Thread.currentThread().getName()+"] " +
                    "Timeout: Pool empty. Unable to fetch a connection in " + (maxWait / 1000) +
                    " seconds, none available["+busy.size()+" in use].");
            } else {
                //no timeout, lets try again
                continue;
            }
        }

したがって、これによると、接続はNullです。

の値はcon次の行で取得されます。

PooledConnection con = idle.poll();

コードを追跡すると、idle(構成によって異なりますが、デフォルトでは)FairBlockingQueueが表示されます。ヒントの実装をチェックアウトできます。

一般に、常に ResultSet、Statement、および Connection を閉じる必要があり、使用された接続はプールに正しく解放される必要があります。これを正しく行わないと、接続が閉じられない => 再利用できなくなる可能性があります (接続プールの「リーク」)。

プールの状態に関する詳細なログを作成し、それを監視して問題を切り分けることをお勧めします。

データベース接続プールのリークを防止するための Apache のガイドライン:

removeAbandoned="true"

放棄されたデータベース接続は削除され、再利用されます

removeAbandonedTimeout="60"

データベース接続が放棄されたと見なされるまでのアイドル状態の秒数を設定する

logAbandoned="true"

データベース接続リソースを放棄したコードのスタック トレースをログに記録します。「放棄された接続をログに記録すると、スタック トレースを生成する必要があるため、接続を借用するたびにオーバーヘッドが追加される」ことに注意してください。

値を少し大きくするとmaxWait(1200、1500、1700 - 実験だけです。ユーザーの観点からは応答時間に違いはありません)、まだ問題があるまれなケースが解消されると思います。

于 2012-07-26T14:30:57.300 に答える
6

「ビジーでない接続はどこにありますか?」

それらがドロップされたようで、何らかの理由で接続プールがそれらを再接続しようとしていません。

これを接続先の URL に追加します。

autoReconnect=true

これをプロパティとしてリソースに追加すると、切断された接続が自動的に再接続されます。

validationQuery="SELECT 1"

また、これにより、接続がドロップされていることを確認できるはずです。

logAbandoned="true"

スタック オーバーフローに関する同様の質問が複数あります。

Tomcat 接続プーリング、アイドル接続、および接続作成 JDBC 接続プールが Tomcat で接続を再開しない

ただし、接続が完全に解放されていないことが原因である可能性もあります。 枯渇した接続プールを回避するための JDBC MySql 接続プーリング プラクティス

于 2012-07-26T12:41:47.530 に答える
6

プールのバグのようです。size変数がインクリメントされ、接続を作成しようとしていますが、作成が失敗した場合...size値が大きく、プールに実際の接続がありません-ひどい:

    //if we get here, see if we need to create one
    //this is not 100% accurate since it doesn't use a shared
    //atomic variable - a connection can become idle while we are creating
    //a new connection
    if (size.get() < getPoolProperties().getMaxActive()) {
        //atomic duplicate check
        if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
            //if we got here, two threads passed through the first if
            size.decrementAndGet();
        } else {
            //create a connection, we're below the limit
            return createConnection(now, con, username, password);
        }
    } //end if
于 2012-10-24T12:45:25.800 に答える