聊聊druid连接池的监控
序
本文主要研究一下druid连接池的监控
init
com/alibaba/druid/pool/DruidDataSource.java
public void init() throws SQLException {
//......
registerMbean();
//......
}
DruidDataSource的init方法会执行registerMbean
registerMbean
com/alibaba/druid/pool/DruidDataSource.java
public void registerMbean() {
if (!mbeanRegistered) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
ObjectName objectName = DruidDataSourceStatManager.addDataSource(DruidDataSource.this,
DruidDataSource.this.name);
DruidDataSource.this.setObjectName(objectName);
DruidDataSource.this.mbeanRegistered = true;
return null;
}
});
}
}
registerMbean会执行DruidDataSourceStatManager.addDataSource(DruidDataSource.this, DruidDataSource.this.name)
DruidDataSourceStatManager
com/alibaba/druid/stat/DruidDataSourceStatManager.java
public static synchronized ObjectName addDataSource(Object dataSource, String name) {
final Map<Object, ObjectName> instances = getInstances();
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
synchronized (instances) {
if (instances.size() == 0) {
try {
ObjectName objectName = new ObjectName(MBEAN_NAME);
if (!mbeanServer.isRegistered(objectName)) {
mbeanServer.registerMBean(instance, objectName);
}
} catch (JMException ex) {
LOG.error("register mbean error", ex);
}
DruidStatService.registerMBean();
}
}
ObjectName objectName = null;
if (name != null) {
try {
objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + name);
mbeanServer.registerMBean(dataSource, objectName);
} catch (Throwable ex) {
LOG.error("register mbean error", ex);
objectName = null;
}
}
if (objectName == null) {
try {
int id = System.identityHashCode(dataSource);
objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + id);
mbeanServer.registerMBean(dataSource, objectName);
} catch (Throwable ex) {
LOG.error("register mbean error", ex);
objectName = null;
}
}
instances.put(dataSource, objectName);
return objectName;
}
DruidDataSourceStatManager的addDataSource方法通过mbeanServer.registerMBean(dataSource, objectName)将DruidDataSource注册到mbeanServer中,而DruidDataSource则实现了DruidDataSourceMBean接口
DruidDataSourceMBean
public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean {
long getResetCount();
boolean isEnable();
String getUrl();
void shrink();
int removeAbandoned();
String dump();
int getWaitThreadCount();
int getLockQueueLength();
long getNotEmptyWaitCount();
int getNotEmptyWaitThreadCount();
long getNotEmptySignalCount();
long getNotEmptyWaitMillis();
long getNotEmptyWaitNanos();
void resetStat();
boolean isResetStatEnable();
void setResetStatEnable(boolean resetStatEnable);
String getVersion();
void setPoolPreparedStatements(boolean poolPreparedStatements);
int getActivePeak();
int getPoolingPeak();
Date getActivePeakTime();
Date getPoolingPeakTime();
long getErrorCount();
ObjectName getObjectName();
void clearStatementCache() throws SQLException;
long getDiscardCount();
void setStatLoggerClassName(String className);
long getTimeBetweenLogStatsMillis();
void setTimeBetweenLogStatsMillis(long timeBetweenLogStatsMillis);
void setConnectionProperties(String connectionProperties);
int fill() throws SQLException;
int fill(int toCount) throws SQLException;
boolean isUseGlobalDataSourceStat();
}
DruidDataSourceMBean按jmx规范命名以MBean结尾,它定义了一系列的getter和操作方法,它还继承了DruidAbstractDataSourceMBean
DruidAbstractDataSourceMBean
com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java
public interface DruidAbstractDataSourceMBean {
int getLoginTimeout();
String getDbType();
String getName();
int getInitialSize();
String getUsername();
String getUrl();
String getDriverClassName();
long getConnectCount();
long getCloseCount();
long getConnectErrorCount();
int getPoolingCount();
long getRecycleCount();
int getActiveCount();
long getCreateCount();
long getDestroyCount();
long getCreateTimespanMillis();
long getCommitCount();
long getRollbackCount();
long getStartTransactionCount();
int getQueryTimeout();
int getTransactionQueryTimeout();
String getValidationQuery();
int getValidationQueryTimeout();
int getMaxWaitThreadCount();
long getTimeBetweenEvictionRunsMillis();
long getMinEvictableIdleTimeMillis();
boolean isRemoveAbandoned();
long getRemoveAbandonedTimeoutMillis();
List<String> getActiveConnectionStackTrace();
List<String> getFilterClassNames();
boolean isTestOnBorrow();
void setTestOnBorrow(boolean testOnBorrow);
boolean isTestOnReturn();
boolean isTestWhileIdle();
void setTestWhileIdle(boolean testWhileIdle);
boolean isDefaultAutoCommit();
Boolean getDefaultReadOnly();
Integer getDefaultTransactionIsolation();
String getDefaultCatalog();
boolean isPoolPreparedStatements();
boolean isSharePreparedStatements();
long getMaxWait();
int getMinIdle();
int getMaxIdle();
long getCreateErrorCount();
int getMaxActive();
void setMaxActive(int maxActive);
long getTimeBetweenConnectErrorMillis();
int getMaxOpenPreparedStatements();
long getRemoveAbandonedCount();
boolean isLogAbandoned();
void setLogAbandoned(boolean logAbandoned);
long getDupCloseCount();
boolean isBreakAfterAcquireFailure();
int getConnectionErrorRetryAttempts();
int getMaxPoolPreparedStatementPerConnectionSize();
void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize);
String getProperties();
int getRawDriverMinorVersion();
int getRawDriverMajorVersion();
Date getCreatedTime();
String getValidConnectionCheckerClassName();
long[] getTransactionHistogramValues();
void setTransactionThresholdMillis(long transactionThresholdMillis);
long getTransactionThresholdMillis();
long getPreparedStatementCount();
long getClosedPreparedStatementCount();
long getCachedPreparedStatementCount();
long getCachedPreparedStatementDeleteCount();
long getCachedPreparedStatementAccessCount();
long getCachedPreparedStatementMissCount();
long getCachedPreparedStatementHitCount();
boolean isUseOracleImplicitCache();
void setUseOracleImplicitCache(boolean useOracleImplicitCache);
int getDriverMajorVersion();
int getDriverMinorVersion();
String getExceptionSorterClassName();
}
DruidAbstractDataSourceMBean定义了暴露给jmx的一系列方法
getStatDataForMBean
com/alibaba/druid/pool/DruidDataSource.java
public Map<String, Object> getStatDataForMBean() {
try {
Map<String, Object> map = new HashMap<String, Object>();
// 0 - 4
map.put("Name", this.getName());
map.put("URL", this.getUrl());
map.put("CreateCount", this.getCreateCount());
map.put("DestroyCount", this.getDestroyCount());
map.put("ConnectCount", this.getConnectCount());
// 5 - 9
map.put("CloseCount", this.getCloseCount());
map.put("ActiveCount", this.getActiveCount());
map.put("PoolingCount", this.getPoolingCount());
map.put("LockQueueLength", this.getLockQueueLength());
map.put("WaitThreadCount", this.getNotEmptyWaitThreadCount());
// 10 - 14
map.put("InitialSize", this.getInitialSize());
map.put("MaxActive", this.getMaxActive());
map.put("MinIdle", this.getMinIdle());
map.put("PoolPreparedStatements", this.isPoolPreparedStatements());
map.put("TestOnBorrow", this.isTestOnBorrow());
// 15 - 19
map.put("TestOnReturn", this.isTestOnReturn());
map.put("MinEvictableIdleTimeMillis", this.minEvictableIdleTimeMillis);
map.put("ConnectErrorCount", this.getConnectErrorCount());
map.put("CreateTimespanMillis", this.getCreateTimespanMillis());
map.put("DbType", this.dbTypeName);
// 20 - 24
map.put("ValidationQuery", this.getValidationQuery());
map.put("ValidationQueryTimeout", this.getValidationQueryTimeout());
map.put("DriverClassName", this.getDriverClassName());
map.put("Username", this.getUsername());
map.put("RemoveAbandonedCount", this.getRemoveAbandonedCount());
// 25 - 29
map.put("NotEmptyWaitCount", this.getNotEmptyWaitCount());
map.put("NotEmptyWaitNanos", this.getNotEmptyWaitNanos());
map.put("ErrorCount", this.getErrorCount());
map.put("ReusePreparedStatementCount", this.getCachedPreparedStatementHitCount());
map.put("StartTransactionCount", this.getStartTransactionCount());
// 30 - 34
map.put("CommitCount", this.getCommitCount());
map.put("RollbackCount", this.getRollbackCount());
map.put("LastError", JMXUtils.getErrorCompositeData(this.getLastError()));
map.put("LastCreateError", JMXUtils.getErrorCompositeData(this.getLastCreateError()));
map.put("PreparedStatementCacheDeleteCount", this.getCachedPreparedStatementDeleteCount());
// 35 - 39
map.put("PreparedStatementCacheAccessCount", this.getCachedPreparedStatementAccessCount());
map.put("PreparedStatementCacheMissCount", this.getCachedPreparedStatementMissCount());
map.put("PreparedStatementCacheHitCount", this.getCachedPreparedStatementHitCount());
map.put("PreparedStatementCacheCurrentCount", this.getCachedPreparedStatementCount());
map.put("Version", this.getVersion());
// 40 -
map.put("LastErrorTime", this.getLastErrorTime());
map.put("LastCreateErrorTime", this.getLastCreateErrorTime());
map.put("CreateErrorCount", this.getCreateErrorCount());
map.put("DiscardCount", this.getDiscardCount());
map.put("ExecuteQueryCount", this.getExecuteQueryCount());
map.put("ExecuteUpdateCount", this.getExecuteUpdateCount());
return map;
} catch (JMException ex) {
throw new IllegalStateException("getStatData error", ex);
}
}
DruidDataSource的getStatDataForMBean定义了给jmx的所有监控项
DruidDataSourceUtils
com/alibaba/druid/util/DruidDataSourceUtils.java
public static Map<String, Object> getStatDataForMBean(Object druidDataSource) {
if (druidDataSource.getClass() == DruidDataSource.class) {
return ((DruidDataSource) druidDataSource).getStatDataForMBean();
}
try {
Method method = druidDataSource.getClass().getMethod("getStatDataForMBean");
Object obj = method.invoke(druidDataSource);
return (Map<String, Object>) obj;
} catch (Exception e) {
LOG.error("getStatDataForMBean error", e);
return null;
}
}
DruidDataSourceUtils提供了静态方法用于获取监控项
小结
DruidDataSource的init方法会执行registerMbean,把自身注册到mbeanServer,它实现了DruidDataSourceMBean接口;而DruidDataSourceUtils提供了静态方法用于获取监控项,它使用的是DruidDataSource的getStatDataForMBean方法(貌似没直接给到jmx
),可以利用该方法把指标暴露给micrometer,之后就可以利用micrometer的集成能力输出到各个监控平台。