美文网首页
聊聊druid连接池的监控

聊聊druid连接池的监控

作者: go4it | 来源:发表于2023-09-28 10:55 被阅读0次

    本文主要研究一下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的集成能力输出到各个监控平台。

    相关文章

      网友评论

          本文标题:聊聊druid连接池的监控

          本文链接:https://www.haomeiwen.com/subject/ldelbdtx.html