2012-07-11 37 views
21

Mi aplicación web Java que ejecuta Tomcat (7.0.28) deja de responder periódicamente. Espero algunas sugerencias de posibles culpables (¿sincronización?), Así como quizás algunas herramientas recomendadas para recopilar más información sobre lo que ocurre durante un bloqueo. Algunos hechos que he acumulado:La aplicación web Java en tomcat se congela periódicamente

  • Cuando la aplicación web se congela, Tomcat sigue alimentando los hilos de solicitud en la aplicación, pero la aplicación no libera ellos. El grupo de subprocesos se llena hasta el máximo (actualmente 250), y las solicitudes subsiguientes fallan inmediatamente. Durante el funcionamiento normal, nunca hay más de 2 o 3 hilos activos.

  • No hay errores o excepciones de ningún tipo registradas en ninguno de los registros de Tomcat o de la aplicación web cuando ocurre el problema.

  • Al hacer una "Parada" y luego un "Inicio" en nuestra aplicación a través de la aplicación web de administración de tomcat resuelve inmediatamente este problema (hasta el día de hoy).

  • Últimamente la frecuencia ha sido dos o tres veces al día, aunque hoy ha sido mucho peor, probablemente 20 veces, y en ocasiones no vuelve a la vida inmediatamente.

  • El problema se produce sólo durante el horario comercial

  • El problema no se produce en nuestro sistema de estadificación

  • Cuando se produce el problema, el uso del procesador y la memoria en el servidor permanece plana (y bastante bajo) . Tomcat informa mucha memoria libre.

  • Tomcat sigue respondiendo cuando se produce el problema. La aplicación web de administración funciona perfectamente, y tomcat continúa enviando solicitudes a nuestra aplicación hasta que se llenen todos los hilos del grupo.

  • Nuestro servidor de base de datos sigue siendo receptivo cuando ocurre el problema. Utilizamos el marco Spring para el acceso e inyección de datos.

  • El problema generalmente ocurre cuando el uso es alto, pero nunca hay un aumento inusualmente alto en el uso.

  • Historial de problemas: algo similar ocurrió hace un año y medio. Después de muchos cambios en la configuración y el código del servidor, el problema desapareció hasta hace aproximadamente un mes. En las últimas semanas se ha producido con mucha más frecuencia, un promedio de 2 o 3 veces al día, a veces varias veces seguidas.

  • Identifiqué algún código de servidor hoy que puede no haber sido seguro para las hebras, y puse una solución para eso, pero el problema todavía está sucediendo (aunque con menos frecuencia). ¿Es este el tipo de problema que puede causar un código inseguro?

ACTUALIZACIÓN: Con varios mensajes que indican la conexión de base de datos de la piscina agotamiento, lo hice un poco de búsqueda en esa dirección y encontramos esta otra Stackoverflow question que explica casi todos los problemas que estoy experimentando.

Aparentemente, los valores predeterminados para las conexiones maxActive y maxIdle en la implementación BasicDataSource de Apache son cada 8. Además, maxWait se establece en -1, por lo que cuando se agota el grupo y entra una nueva solicitud de conexión, esperará para siempre sin registrar ningún tipo de excepción.Todavía voy a esperar a que este problema vuelva a suceder y realizar un volcado de jstack en la JVM para poder analizar esa información, pero parece que este es el problema. Lo único que no explica es por qué la aplicación a veces no se recupera de este problema. Supongo que las solicitudes simplemente se acumulan a veces y una vez que se atrasa nunca pueden ponerse al día.

ACTUALIZACIÓN II: me encontré con un jstack durante un accidente y se encontró cerca de 250 hilos (máximo) de los siguientes:

"http-nio-443-exec-294" daemon prio=10 tid=0x00002aaabd4ed800 nid=0x5a5d in Object.wait() [0x00000000579e2000] 
    java.lang.Thread.State: WAITING (on object monitor) 
     at java.lang.Object.wait(Native Method) 
     at java.lang.Object.wait(Object.java:485) 
     at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1118) 
     - locked <0x0000000743116b30> (a org.apache.commons.pool.impl.GenericObjectPool$Latch) 
     at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106) 
     at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
     at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) 
     at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) 
     at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:718) 

Para mi ojo no entrenado, esto parece bastante concluyente. Parece que el grupo de conexiones de la base de datos ha tocado su límite. Configuré un maxWait de tres segundos sin modificar maxActive y maxIdle solo para asegurarnos de comenzar a ver las excepciones registradas cuando el grupo se llena. Luego estableceré esos valores en algo apropiado y supervisaré.

ACTUALIZACIÓN III: Después de configurar maxWait, empecé a ver estos en mis registros, como se esperaba:

org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object 
     at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114) 
     at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
     at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) 
     at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) 

he fijado maxActive a -1 (infinito) y maxIdle a 10. lo haré monitorear por un tiempo, pero mi suposición es que este es el final del problema.

+7

'kill -3 ' es tu amigo. Ejecuta esto y mira el volcado de hilo. Es posible que desee consultar el Thread Dump Analyzer para obtener información agrupada (http://java.net/projects/tda/). – mindas

+0

Wild-guess sin ninguna otra información (¡necesita volcados de hilos!): Agotamiento del conjunto de conexiones DB. –

+1

Esto es exactamente lo que me estaba pasando, la aplicación de aplicaciones creció demasiado, las conexiones máximas eran demasiado bajas y el tiempo de espera no se había definido, los hilos seguían acumulándose ahora y el servidor se congelaba. Aumento de contras máximos y establecer un tiempo específico en la espera máxima y ahora solo estoy monitoreando, pero el servidor funciona bien. Gracias por este mini tutorial. – Lauro182

Respuesta

12

Desde la experiencia, es posible que desee ver su grupo de conexión de base de datos implementación. Podría ser que su base de datos tenga mucha capacidad, pero el grupo de conexiones de su aplicación está limitado a un pequeño número de conexiones. No puedo recordar los detalles, pero parece que recuerdo tener un problema similar, que fue una de las razones por las que cambié al usar BoneCP, que he encontrado que es muy rápido y confiable en las pruebas de carga.

Después de intentar la depuración que se sugiere a continuación, intente aumentar el número de conexiones disponibles en el grupo y vea si eso tiene algún impacto.

que identifica un cierto código del servidor actual que pueden no haber sido multi-hilo, y me puso en una solución para eso, pero el problema sigue ocurriendo (aunque con menos frecuencia). ¿Es este el tipo de problema que puede causar código inseguro?

Depende de lo que quiera decir con seguridad de subprocesos. Me parece que su aplicación está causando hilos en deadlock. Es posible que desee ejecutar su entorno de producción con la JVM configurada para permitir que un depurador se conecte, y luego usar JVisualVM, JConsole u otra herramienta de creación de perfiles (YourKit es una excelente IMO) para echar un vistazo a los hilos que tiene, y lo que Estoy esperando.

+0

Sí BoneCP rocks. commons-dbcp es una mierda Tomcat 7 se envía con un dbcp https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html pero para usarlo el controlador debe ser accesible desde el mismo cargador de clases que tomcat-jdbc.jar. No quiero molestarme en poner el contenedor del controlador en el directorio lib de tomcat cada vez que instalo un tomcat nuevo. – redochka

+0

Redsonic: Eso no es verdad. Si su 'DataSource' se define dentro de un contexto, y no como un recurso JNDI compartido entre contextos, puede estar en el classpath del contexto (es decir, en el .war). Así es como lo he usado en los sistemas de producción. –

+0

ah ok. No me probé a mí mismo. Informé lo que estaba en el tomcat 7 doc. Ok, entonces, en este caso, es una opción también :) – redochka

Cuestiones relacionadas