Springブート、JDBCテンプレート、SQL ServerとともにTomcat JDBC接続プールを使用しています。アプリケーションがデータベース接続を待っている間に、接続プール内で何が起こっているかを知る必要があります。といった....
Log4jのようなロギングフレームワークをデバッグまたは使用して、これらの情報を取得する方法はありますか?
どんなアイデアでも大歓迎です。
多くの調査の結果、データベース接続プールをログおよび監視する3つの方法を見つけることができました。
https://Tomcat.Apache.org/Tomcat-8.0-doc/jdbc-pool.html
Spring Bootpropertiesを使用したモニタリング。
[〜#〜] jmx [〜#〜](Java Management Extensions)(@nitinが提案したとおり) )
SpringAspectsを使用したモニタリング。
第一の方法:Spring Bootプロパティを使用した監視
データベース接続プールを記録および監視するのに非常に役立つSpringブートプロパティを以下で見つけました。
これらのプロパティ(およびその他のプロパティ)は文書化されていません。詳細については、以下のgithubの問題を参照してください。 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
このリストには、データソースのみに関連するプロパティが含まれています。(上記のリンクから取得)
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
2番目の方法:JMXを使用した監視(Java Management Extensions)
Tomcat JDBCプールは、MBean、つまりConnectionPoolMBeanを提供します。
Spring BootはJMX MBeanを自動的に登録するため、このMBeanをMBeanサーバーに登録/エクスポートする必要はありません。 JDKに付属しているJConsoleを開くだけです。Windowsの場合->コマンドプロンプト-> jconsoleで開きます。詳細については、以下のスクリーンショットを参照してください。
また、このMBeanは、接続が破棄されたり、接続が失敗したり、クエリに時間がかかったりしたときなどにnotifiesします。以下のスクリーンショットを参照してください。
3番目の方法:Springアスペクトを使用した監視(開発/ QA環境のみ)
この側面を使用して、TomcatJdbc接続プールを記録します。
すべてのデータベースコールをインターセプトするSpring Aspectを作成しました。これにより、パフォーマンスに確実に影響します。
したがって、開発/ QA環境でこの側面を使用し、不要な場合はこのメソッドをコメントアウトします(たとえば、実稼働デプロイメント中)。
@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();
}
これで、アプリケーションで接続リークが発生する特定のデータベース呼び出しを簡単に識別できます。
すばらしい回答をありがとう@Sundararaj Govindasamy。それに基づいて、Spring Boot Applicationにコンポーネントを作成して、データベースプール情報をデバッグしました。
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()));
}
}
これは純粋なJSPページMBeanデバッガーであり、外部の依存関係なしですべてのTomcatリリースで簡単に使用できます。 dumpMBean.jsp?name=ConnectionPool
を呼び出してdbpoolをリストするか、名前を空のままにしてすべてのMBeanをダンプします。
<%@ page contentType="text/plain; charset=UTF-8" pageEncoding="ISO-8859-1"
session="false"
import="Java.io.*, Java.util.*, Java.net.*,
javax.management.*, Java.lang.management.ManagementFactory
"
%><%!
private void dumpMBean(MBeanServer server, ObjectName objName, MBeanInfo mbi, Writer writer) throws Exception {
writer.write(String.format("MBeanClassName=%s%n", mbi.getClassName()));
Map<String,String> props=new HashMap<String,String>();
int idx=0;
for(MBeanAttributeInfo mf : mbi.getAttributes()) {
idx++;
try {
Object attr = server.getAttribute(objName, mf.getName());
if (attr!=null)
props.put(mf.getName(), attr.toString());
} catch(Exception ex) {
// Sun.management.RuntimeImpl: Java.lang.UnsupportedOperationException(Boot class path mechanism is not supported)
props.put("error_"+idx, ex.getClass().getName()+" "+ex.getMessage());
}
}
// sort by hashmap keys
for(String sKey : new TreeSet<String>(props.keySet()))
writer.write(String.format("%s=%s%n", sKey, props.get(sKey)));
}
%><%
// Dump MBean management properties, all beans or named beans
// dumpMBean.jsp?name=ConnectionPool,ContainerMBean
// dumpMBean.jsp?name=
if (request.getCharacterEncoding()==null)
request.setCharacterEncoding("UTF-8");
String val = request.getParameter("name");
String[] names = val!=null ? val.trim().split(",") : new String[0];
if (names.length==1 && names[0].isEmpty()) names=new String[0];
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
for(ObjectName objName : server.queryNames(null,null)) {
MBeanInfo mbi = server.getMBeanInfo(objName);
boolean match = names.length<1;
String name = mbi.getClassName();
for(int idx=0; idx<names.length; idx++) {
if (name.endsWith(names[idx])) {
match=true;
break;
}
}
if (match) {
dumpMBean(server, objName, mbi, out);
out.println("");
}
}
out.flush();
%>