2012-07-12 12 views
20

Chúng tôi vừa chuyển từ dbcp sang kết nối jdbc tomcat gộp. Chúng tôi đã thử các hệ thống trong tải và nhận được ngoại lệ sau đây:Thiếu kết nối trong hồ bơi kết nối jdbc tomcat

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) 

thông báo này:

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

Đâu là những kết nối mà không phải bận rộn? Số điện thoại bận vẫn tiếp tục giảm sau này, nhưng chúng tôi vẫn không quản lý được bất kỳ kết nối nào.

Bất kỳ ý tưởng nào?

Cấu hình:

<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 và tomcat 6. db - mysql

+0

Bạn đã cố gắng tăng kích thước nhóm kết nối chưa? Điều gì sẽ xảy ra nếu bạn tăng kích thước? – dgregory

+0

Tôi không thể tăng số lượng kết nối vì tôi có nhiều máy chủ và tôi đang ở giới hạn trên cùng của cơ sở dữ liệu. Tuy nhiên, tôi nghĩ điều này sẽ xảy ra với số lượng lớn hơn. –

+0

Chúng tôi có thể đoán hoặc bạn có thể đăng cấu hình của mình. –

Trả lời

16

Lấy một cái nhìn tại các nguồn ConnectionPool.java bạn dường như đánh đoạn mã này trong phương pháp 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; 
      } 
     } 

Vì vậy, theo đó, kết nối của bạn Null.

Giá trị của con được lấy trên dòng:

PooledConnection con = idle.poll(); 

nếu bạn theo dõi mã này, bạn sẽ thấy idle được (tùy thuộc vào cấu hình của bạn, nhưng theo mặc định) FairBlockingQueue. Bạn có thể kiểm tra việc thực hiện các gợi ý.

Nói chung, bạn luôn phải đóng Kết quả, Báo cáo và Kết nối và kết nối đã sử dụng phải được giải phóng chính xác trở lại hồ bơi. Không làm như vậy một cách chính xác có thể dẫn đến kết nối không bao giờ được đóng => không bao giờ có sẵn một lần nữa để tái sử dụng (hồ bơi kết nối "rò rỉ").

Tôi đề nghị bạn xây dựng một số ghi nhật ký chi tiết về trạng thái của hồ bơi và theo dõi nó để cô lập vấn đề.

Một số hướng dẫn từ Apache để ngăn ngừa kết nối cơ sở dữ liệu rò rỉ hồ bơi:

removeAbandoned="true" 

kết nối cơ sở dữ liệu bị bỏ rơi được loại bỏ và tái chế

removeAbandonedTimeout="60" 

thiết lập số giây một kết nối cơ sở dữ liệu đã được nhàn rỗi trước khi nó được được coi là bị bỏ rơi

logAbandoned="true" 

đăng nhập với tên theo dõi mã đã bỏ qua tài nguyên kết nối cơ sở dữ liệu. Hãy ghi nhớ rằng "việc ghi nhật ký các Kết nối bị bỏ rơi sẽ cộng thêm chi phí cho mọi Kết nối mượn vì một dấu vết ngăn xếp phải được tạo ra."

Tôi vẫn nghĩ tăng nhẹ giá trị maxWait (1200, 1500, 1700 - chỉ thử nghiệm, sẽ không có sự khác biệt về thời gian phản hồi từ góc nhìn của người dùng) sẽ xóa các trường hợp hiếm hoi đó.

5

"? Ở đâu các kết nối mà không phải bận rộn"

Có vẻ như chúng đã bị xóa và vì lý do nào đó, hồ bơi kết nối của bạn không cố gắng kết nối lại chúng.

Thêm phần này vào URL mà bạn đang kết nối:

autoReconnect=true 

Và thêm này như là một tài sản để tài nguyên nên gây ra các kết nối khống sẽ kết nối lại tự động.

validationQuery="SELECT 1" 

Ngoài ra điều này nên cho phép bạn xem các kết nối bị rơi:

logAbandoned="true" 

Có nhiều câu hỏi tương tự như trên stack overflow.

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

Tuy nhiên nó cũng có thể rằng bạn không giải phóng các kết nối hoàn toàn đó là nguyên nhân trong số họ chết. JDBC MySql connection pooling practices to avoid exhausted connection pool

5

có vẻ là một lỗi trong hồ bơi, size biến được tăng lên, sau đó cố gắng để tạo ra kết nối, nhưng nếu tạo không ... chúng tôi có size giá trị lớn và không có kết nối thực tế trong hồ bơi - khủng khiếp:

//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' được giảm trong' createConnection() 'nếu tạo không thành công, vì vậy nó * có vẻ * chính xác, tuy nhiên tôi nghi ngờ rằng một số điều kiện chủng tộc gây ra một giá trị sai 'size' bởi vì tôi nhận' PoolExhaustedException' với 'size = 10, busy = 0, idle = 0' (nhóm trống nên nó sẽ cố gắng tạo một kết nối mới thay vì wating cho một idle nhưng nó * nghĩ * nó không trống vì giá trị của kích thước). – Pino