2012-07-12 81 views
20

我們剛剛從dbcp遷移到tomcat jdbc連接池。 我們試圖在系統負載並收到以下異常:在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分貝 - mysql的

+0

您是否嘗試增加連接池大小?如果你增加尺寸會發生什麼? – dgregory 2012-07-12 11:58:48

+0

我無法增加連接數,因爲我有多個服務器,而且我處於數據庫的最高限制。但是,我認爲這會發生在更大的數字上。 – 2012-07-12 12:44:08

+0

我們可以猜測,或者您可以發佈您的配置。 – 2012-07-13 13:45:54

回答

16

考慮看看的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; 
      } 
     } 

所以根據這一點,您的連接

con值上線檢索:

PooledConnection con = idle.poll(); 

,如果你跟蹤代碼,你會看到idle是(根據您的配置,但默認情況下)FairBlockingQueue。您可以檢查提示的實現。

一般來說,您總是必須關閉ResultSet,Statements和Connections,並且使用的連接應該正確地釋放回池中。 如果不正確,可能會導致連接永遠不會關閉=>永遠不會再次可用(連接池「泄漏」)。

我建議你在池的狀態上構建一些詳細的日誌並監視它以隔離問題。

來自Apache的防止數據庫連接池泄露的一些指導原則:

removeAbandoned="true" 

廢棄的數據庫連接拆除和回收

removeAbandonedTimeout="60" 

集的秒數數據庫連接已空閒之前,它是考慮放棄

logAbandoned="true" 

log as對放棄數據庫連接資源的代碼的追蹤。請記住,「由於必須生成堆棧跟蹤,所以」對已棄用連接的日誌記錄會增加每個連接借用的開銷「。

我仍然認爲稍微增加maxWait的值(1200,1500,1700 - 只是實驗,從用戶角度來看響應時間沒有差異)將清除那些你仍然有問題的罕見情況。

5

「在哪裏?是不是很忙的連接」

這聽起來像是他們已經被刪除,並且由於某種原因,您的連接池不會嘗試重新連接它們。

這個添加到你連接到網址:

autoReconnect=true 

並添加此作爲一個屬性的資源應該引起死連接被自動重新連接。

validationQuery="SELECT 1" 

而且這應該可以讓你看到的連接被丟棄:

logAbandoned="true" 

有一個關於堆棧溢出多個類似的問題。

Tomcat connection pooling,idle connections,and connection creation JDBC Connection pool not reopening Connections in tomcat

但是它也可能是你沒有完全釋放連接,這是他們的死亡原因。 JDBC MySql connection pooling practices to avoid exhausted connection pool

5

似乎是在游泳池中的錯誤,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 
+2

如果創建失敗,'size'在'createConnection()'中遞減,所以它*似乎*正確,但我懷疑某些競態條件會導致錯誤的值'size',因爲我得到了'Size = 10,busy = 0,idle = 0'的'PoolExhaustedException'(這個池是空的,所以它應該嘗試創建一個新的連接, *由於尺寸的大小,它不是空的)。 – Pino 2013-09-10 11:04:08