2012-07-12 11 views
20

Acabamos de migrar de dbcp a tomcat jdbc connection pooling. Probamos el sistema de carga y recibimos la siguiente excepción:Faltan conexiones en el conjunto de conexiones 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) 

cuenta de esto:

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

¿Dónde están las conexiones que no están ocupados? El número de ocupado siguió bajando después de esto, pero todavía no logramos obtener ninguna conexión.

¿Alguna idea?

Configuración:

<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 y Tomcat 6. db - MySQL

+0

¿Intentó aumentar el tamaño del grupo de conexiones? ¿Qué pasa si aumenta el tamaño? – dgregory

+0

No puedo aumentar el número de conexiones, ya que tengo varios servidores y estoy en el límite superior de la base de datos. Sin embargo, creo que esto sucederá en un número mayor. –

+0

Podríamos adivinar, o podría publicar su configuración. –

Respuesta

16

Echando un vistazo a la fuente de ConnectionPool.java que parecen ir a este fragmento de código en el método 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; 
      } 
     } 

Así que de acuerdo a esto, la conexión es nulo .

El valor de con se recupera en la línea:

PooledConnection con = idle.poll(); 

si la pista del código, verá idle es (dependiendo de su configuración, pero por defecto) FairBlockingQueue. Puede consultar la implementación para obtener sugerencias.

En general, siempre debe cerrar ResultSets, las declaraciones y las conexiones y las conexiones utilizadas se deben volver a lanzar correctamente al grupo. Si no lo hace correctamente, las conexiones nunca se cerrarán => nunca estarán disponibles nuevamente para su reutilización (el grupo de conexiones "tiene fugas").

Le sugiero que construya un registro detallado sobre el estado del grupo y lo supervise para aislar el problema.

Algunas pautas de Apache para prevenir la conexión de base de la piscina fugas:

removeAbandoned="true" 

conexiones de base abandonados son retirados y reciclados

removeAbandonedTimeout="60" 

establecer el número de segundos que una conexión de base ha estado inactivo antes de que sea se considera abandonado

logAbandoned="true" 

log as tachuela del código que abandonó los recursos de conexión de la base de datos. Tenga en cuenta que "el registro de conexiones abandonadas agrega gastos generales para cada préstamo de conexión porque se debe generar un seguimiento de pila".

Todavía creo que aumentar un poco el valor maxWait (1200, 1500, 1700 - simplemente experimente, no habrá diferencia en los tiempos de respuesta desde la perspectiva del usuario) borrará esos casos raros, en los que todavía tiene problemas.

5

"? ¿Dónde están las conexiones que no están ocupados"

Parece que se han caído y, por algún motivo, su grupo de conexiones no intenta volver a conectarlos.

añadir esto a la dirección URL que se va a conectar a:

autoReconnect=true 

y añadir como una propiedad al recurso debe provocar que las conexiones muertas para volver a conectarse automáticamente.

validationQuery="SELECT 1" 

También esto debería permitirle ver las conexiones que son caídas:

logAbandoned="true" 

Hay varias preguntas similares sobre desbordamiento de pila.

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

Sin embargo, también puede ser que no se está liberando las conexiones por completo que es la causa de ellos mueren. JDBC MySql connection pooling practices to avoid exhausted connection pool

5

parece ser un error en la piscina, se incrementa size variable, entonces tratar de crear la conexión, pero si falla la creación ... tenemos size valor grande y no hay conexiones reales en la piscina - Muy malo:

//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' se decrementa en' createConnection() 'si la creación falla, entonces * parece * correcto, sin embargo, sospecho que alguna condición de carrera causa un valor incorrecto de 'size' porque obtengo' PoolExhaustedException' con 'size = 10, busy = 0, idle = 0' (el pool está vacío, por lo que debería intentar crear una nueva conexión en lugar de wating para uno inactivo, pero * piensa * no está vacío debido al valor de tamaño). – Pino

Cuestiones relacionadas