2012-07-12 14 views
20

Nous venons de migrer de dbcp vers pooling de connexions jcatbc tomcat. Nous avons essayé le système en charge et reçu l'exception suivante:Connexions manquantes dans le pool de connexions 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) 

Avis ceci:

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

Où sont les connexions qui ne sont pas occupés? Le nombre occupé a continué à descendre après cela, mais nous n'avons toujours pas réussi à obtenir des connexions.

Des idées?

Configuration:

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

+0

Avez-vous essayé d'augmenter la taille du pool de connexions? Que se passe-t-il si vous augmentez la taille? – dgregory

+0

Je ne peux pas augmenter le nombre de connexions, car j'ai plusieurs serveurs, et je suis à la limite supérieure de la base de données. Cependant, je pense que cela se produira à un plus grand nombre .. –

+0

Nous pourrions deviner, ou vous pourriez poster votre configuration. –

Répondre

16

Jeter un oeil à la source de ConnectionPool.java vous semblent frapper ce bout de code dans la méthode 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; 
      } 
     } 

Ainsi, selon cela, votre connexion est nul.

La valeur de con est récupéré sur la ligne:

PooledConnection con = idle.poll(); 

si vous suivez le code, vous verrez idle est (selon votre configuration, mais par défaut) FairBlockingQueue. Vous pouvez vérifier l'implémentation pour obtenir des conseils.

En général, vous devez toujours fermer ResultSets, Statements et Connections et les connexions utilisées doivent être correctement relancées dans le pool. Si vous ne le faites pas correctement, les connexions ne seront jamais fermées => ne plus jamais être disponible pour réutilisation (pool de connexions "leaks").

Je vous suggère de construire une journalisation détaillée sur l'état du pool et de le surveiller pour isoler le problème.

Quelques directives d'Apache pour prévenir les fuites de pool de connexions de base de données:

removeAbandoned="true" 

connexions de base de données abandonnés sont enlevés et recyclés

removeAbandonedTimeout="60" 

définir le nombre de secondes une connexion de base de données a été inactive avant qu'il ne soit considéré comme abandonné

logAbandoned="true" 

Trace trace du code qui a abandonné les ressources de connexion à la base de données. Gardez à l'esprit que "la journalisation des connexions abandonnées ajoute un coût supplémentaire pour chaque emprunt emprunté car une trace de pile doit être générée". Je pense toujours légèrement augmenter la valeur maxWait (1200, 1500, 1700 - juste expérimenter, il n'y aura aucune différence dans les temps de réponse de la perspective de l'utilisateur) permettra d'effacer ces cas rares, dans lesquels vous avez toujours des problèmes.

5

"? Où sont les connexions qui ne sont pas occupés"

Il semble qu'ils aient été supprimés et, pour une raison quelconque, votre pool de connexions n'essaie pas de les reconnecter.

Ajoutez ceci à l'URL que vous vous connectez à:

autoReconnect=true 

Et ajoutez cela comme une propriété à la ressource devrait causer des connexions mortes à reconnecte automatiquement.

validationQuery="SELECT 1" 

Aussi cela devrait vous permettre de voir les connexions sont abandonnées:

logAbandoned="true" 

Il y a plusieurs questions similaires sur un débordement de pile.

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

Cependant, il se peut aussi que vous n'êtes pas complètement délier la connexions qui est la cause de leur mort. JDBC MySql connection pooling practices to avoid exhausted connection pool

5

semble être un bug dans la piscine, la variable size est incrémenté, puis essayer de créer une connexion, mais en cas d'échec création ... nous avons size grande valeur et aucune connexion réelle dans la piscine - terribles:

//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' est décrémenté dans' createConnection() 'si la création échoue, donc * semble * correct, cependant je suspecte que certaines conditions de concurrence causent une mauvaise valeur de 'size' parce que j'obtiens' PoolExhaustedException' avec 'size = 10, busy = 0, idle = 0' (le pool est vide donc il devrait essayer de créer une nouvelle connexion au lieu de wating pour un idle mais il pense * il n'est pas vide en raison de la valeur de la taille). – Pino

Questions connexes