debugging - example - ¿Cómo depurar/registrar las conexiones del grupo de conexiones JDBC de Tomcat?
tomcat jdbc tutorial (2)
Estoy usando el grupo de conexiones JDBC de Tomcat junto con el arranque Spring, la plantilla JDBC y el servidor SQL. Necesito saber qué ocurre dentro del grupo de conexiones mientras la aplicación está esperando la conexión de la base de datos. Como....
- No de conexiones activas.
- No de conexiones inactivas
- No de conexiones bloqueadas, información adicional de por qué esta conexión está bloqueada
- No de conexiones disponibles.
- y ...
¿Hay alguna forma de obtener esta información mediante la depuración o el uso de marcos de registro como log4j?
Cualquier idea será apreciada.
Después de mucha investigación, puedo encontrar 3 formas de registrar y monitorear el conjunto de conexiones de la base de datos.
https://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html
Monitoreo usando las propiedades de Spring Boot .
Monitoreo usando JMX (Java Management Extensions) (como se sugiere @nitin)
Monitorización utilizando Spring Aspects .
1st Way: Monitoreo usando las propiedades Spring Boot.
Encontré a continuación las propiedades de arranque de Spring que serán muy útiles para registrar y monitorear el conjunto de conexiones de la base de datos.
Estas propiedades (y algunas más también) no fueron documentadas . Por favor, consulte más abajo el tema de github para más detalles. https://github.com/spring-projects/spring-boot/issues/1829
#Maximum no.of active connections
spring.datasource.max-active=10
#Log the stack trace of abandoned connection
spring.datasource.log-abandoned=true
#Remove abandoned connection,So, new connection will be created and made available to threads which are waiting for DB connection
spring.datasource.remove-abandoned=true
#If any connection is not used for 10 seconds, consider that connection as "abandoned"
spring.datasource.remove-abandoned-timeout=10
#Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.max-wait=1000
Esta lista contiene más propiedades relacionadas con la fuente de datos solamente (tomadas del enlace anterior)
spring.datasource.abandon-when-percentage-full
spring.datasource.access-to-underlying-connection-allowed
spring.datasource.alternate-username-allowed
spring.datasource.auto-commit
spring.datasource.catalog
spring.datasource.commit-on-return
spring.datasource.connection-customizer
spring.datasource.connection-customizer-class-name
spring.datasource.connection-init-sql
spring.datasource.connection-init-sqls
spring.datasource.connection-properties
spring.datasource.connection-test-query
spring.datasource.connection-timeout
spring.datasource.data-source
spring.datasource.data-source-class-name
spring.datasource.data-source-j-n-d-i
spring.datasource.data-source-properties
spring.datasource.db-properties
spring.datasource.default-auto-commit
spring.datasource.default-catalog
spring.datasource.default-read-only
spring.datasource.default-transaction-isolation
spring.datasource.driver-class-loader
spring.datasource.fair-queue
spring.datasource.idle-timeout
spring.datasource.ignore-exception-on-pre-load
spring.datasource.init-s-q-l
spring.datasource.initialization-fail-fast
spring.datasource.isolate-internal-queries
spring.datasource.jdbc-interceptors
spring.datasource.jdbc-url
spring.datasource.jdbc4-connection-test
spring.datasource.leak-detection-threshold
spring.datasource.log-abandoned
spring.datasource.log-validation-errors
spring.datasource.log-writer
spring.datasource.login-timeout
spring.datasource.max-age
spring.datasource.max-lifetime
spring.datasource.max-open-prepared-statements
spring.datasource.maximum-pool-size
spring.datasource.metrics-tracker-class-name
spring.datasource.minimum-idle
spring.datasource.num-tests-per-eviction-run
spring.datasource.pool-name
spring.datasource.pool-prepared-statements
spring.datasource.pool-properties
spring.datasource.propagate-interrupt-state
spring.datasource.read-only
spring.datasource.record-metrics
spring.datasource.register-mbeans
spring.datasource.remove-abandoned
spring.datasource.remove-abandoned-timeout
spring.datasource.rollback-on-return
spring.datasource.suspect-timeout
spring.datasource.test-on-connect
spring.datasource.thread-factory
spring.datasource.transaction-isolation
spring.datasource.use-disposable-connection-facade
spring.datasource.use-equals
spring.datasource.use-lock
spring.datasource.validation-interval
spring.datasource.validation-query-timeout
spring.datasource.validator
spring.datasource.validator-class-name
spring.datasource.xa
spring.datasource.xa.data-source-class-name
spring.datasource.xa.properties
2nd Way: Monitoreo usando JMX (Java Management Extensions)
El grupo JDBC de Tomcat proporciona un MBean, a saber, ConnectionPoolMBean.
Spring Boot registra JMX MBeans automáticamente. Por lo tanto, no es necesario registrar / exportar este MBean al servidor de MBean. Simplemente abra el JConsole que viene con JDK, para abrir, en Windows -> Símbolo del sistema -> jconsole, eso es todo. Consulte la siguiente captura de pantalla para obtener más información.
Este MBean también notifica cada vez que se abandona una conexión, falla la conexión, cuando una consulta lleva mucho tiempo, etc. Consulte la captura de pantalla a continuación.
3ª vía: Monitoreo usando Spring Aspects (solo para entornos de desarrollo / control de calidad).
Uso este aspecto para registrar el grupo de conexiones de TomcatJdbc.
Creé un Aspecto Spring que interceptará cada llamada a la base de datos. Esto seguramente afectará el rendimiento .
Entonces, use este aspecto en el entorno de desarrollo / control de calidad, comente este método cuando no sea necesario (por ejemplo: durante la implementación de producción).
@Before("execution(* com.test.app.db.dao.*.*(..))")
public void logBeforeConnection(JoinPoint jp) throws Throwable {
String methodName = "";
methodName += jp.getTarget().getClass().getName();
methodName += ":";
methodName += jp.getSignature().getName();
logger.info("before method call : " + methodName + " : number of connections in use by the application (active) : "+ tomcatJdbcPoolDataSource.getNumActive());
logger.info("before method call : " + methodName + " : the number of established but idle connections : "+ tomcatJdbcPoolDataSource.getNumIdle());
logger.info("before method call : " + methodName + " : number of threads waiting for a connection : "+ tomcatJdbcPoolDataSource.getWaitCount());
}
@After("execution(* com.test.app.db.dao.*.*(..)) ")
public void logAfterConnection(JoinPoint jp) throws Throwable {
String methodName = "";
methodName += jp.getTarget().getClass().getName();
methodName += ":";
methodName += jp.getSignature().getName();
logger.info("after method call : " + methodName + " : number of connections in use by the application (active) : "+ tomcatJdbcPoolDataSource.getNumActive());
logger.info("after method call : " + methodName + " : the number of established but idle connections : "+ tomcatJdbcPoolDataSource.getNumIdle());
logger.info("after method call : " + methodName + " : number of threads waiting for a connection : "+ tomcatJdbcPoolDataSource.getWaitCount());
//tomcatJdbcPoolDataSource.checkAbandoned();
}
Ahora, puede identificar fácilmente la llamada a la base de datos en particular que crea una pérdida de conexión en su aplicación.
Gracias a @Sundaraj Govindasamy por una gran respuesta. Sobre esta base, creé un componente en mi aplicación Spring Boot para depurar la información de mi grupo de bases de datos.
import org.apache.tomcat.jdbc.pool.DataSource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DataSourceAspectLogger {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private DataSource ds;
@Before("execution(* br.com.foo.core.repository.*.*(..))")
public void logBeforeConnection(JoinPoint jp) throws Throwable {
logDataSourceInfos("Before", jp);
}
@After("execution(* br.com.foo.core.repository.*.*(..)) ")
public void logAfterConnection(JoinPoint jp) throws Throwable {
logDataSourceInfos("After", jp);
}
public void logDataSourceInfos(final String time, final JoinPoint jp) {
final String method = String.format("%s:%s", jp.getTarget().getClass().getName(), jp.getSignature().getName());
logger.info(String.format("%s %s: number of connections in use by the application (active): %d.", time, method, ds.getNumActive()));
logger.info(String.format("%s %s: the number of established but idle connections: %d.", time, method, ds.getNumIdle()));
logger.info(String.format("%s %s: number of threads waiting for a connection: %d.", time, method, ds.getWaitCount()));
}
}