SpringBoot+HikariCP+Dropwizard-Metrics统计连接池使用情况

SpringBoot+HikariCP+Dropwizard-Metrics统计连接池使用情况

背景,HikariCP是Java目前使用最广的连接池工具类,SpringBoot默认也是用这个,现在想获取连接池使用情况。

这里假设SpringBoot已集成HikariCP
1.pom.xml加上Dropwizard-Metrics配置

<dependency>
    <groupId>io.dropwizard.metrics</groupId>  
    <artifactId>metrics-core</artifactId>  
</dependency>  
<dependency>  
    <groupId>io.dropwizard.metrics</groupId>  
    <artifactId>metrics-healthchecks</artifactId>  
</dependency>  

2在应用启动的时候连接池注册统计接口

import com.codahale.metrics.MetricRegistry;    
import com.codahale.metrics.Slf4jReporter;    
import com.zaxxer.hikari.HikariDataSource;    
    
import javax.sql.DataSource;    
import org.slf4j.Logger;    
import org.slf4j.LoggerFactory;    
@Component    
public class ApplicationRunner implements ApplicationRunner {    
    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationRunner.class);    
    @Autowired    
    private DataSource dataSource;    
    
    @Override    
    public void run(ApplicationArguments args) throws Exception {    
        try {    
            // see detail https://github.com/brettwooldridge/HikariCP/wiki/Dropwizard-Metrics    
            // 连接池注册统计接口    
            MetricRegistry metricRegistry = new MetricRegistry();    
            if(dataSource instanceof HikariDataSource) {    
                ((HikariDataSource) dataSource).setMetricRegistry(metricRegistry);    
            }    
            // 定时打印连接池使用情况    
            Slf4jReporter reporter = Slf4jReporter.forRegistry(metricRegistry).build();    
            reporter.start(1, TimeUnit.MINUTES);    
    
        } catch (Exception e) {    
            String msg = "服务启动异常";    
            LOGGER.error(msg, e);    
            throw new IllegalStateException(msg, e);    
        }     
    
    
    }    
}  

3 提供http请求获取连接池使用情况

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.http.client.SimpleClientHttpRequestFactory;  
import org.springframework.web.client.RestTemplate;  
  
  
/** 
 * 远程使用的RestTemplatebean,与服务间调用区分开来 
 */  
@Configuration  
public class RestTemplateConfig {  
  
    @Bean("remoteRestTemplate")  
    public RestTemplate remoteRestTemplate() {  
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();  
        factory.setReadTimeout(180000);  
        factory.setConnectTimeout(8000);  
        return new RestTemplate(factory);  
    }  
  
}  
import com.codahale.metrics.*;  
import com.netflix.appinfo.InstanceInfo;  
import com.zaxxer.hikari.HikariDataSource;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.beans.factory.annotation.Qualifier;  
import org.springframework.cloud.client.ServiceInstance;  
import org.springframework.cloud.client.discovery.DiscoveryClient;  
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  
import org.springframework.web.client.RestTemplate;  
  
import javax.sql.DataSource;  
import java.util.List;  
import java.util.Map;  
import java.util.SortedMap;  
import java.util.TreeMap;  
  
  
@RestController  
@RequestMapping("hikariCpStatsController")  
public class HikariCpStatsController {  
private static final String SERVICE_NAME ="xiaoniu";  
    @Autowired  
    private DataSource dataSource;  
  
    @Autowired  
    private DiscoveryClient discoveryClient;  
  
    @Qualifier("remoteRestTemplate")  
    @Autowired  
    private RestTemplate restTemplate;  
  
    @GetMapping("poolStatsHa")  
    public TreeMap<String, Object> poolStatsHa() {  
        MetricRegistry metricRegistry = null;  
        if (dataSource instanceof HikariDataSource) {  
            metricRegistry = (MetricRegistry) ((HikariDataSource) dataSource).getMetricRegistry();  
        }  
        if (metricRegistry == null)  
            return null;  
        TreeMap<String, Object> dataAll = new TreeMap<>();  
        // 节点的信息  
        List<ServiceInstance> instances = discoveryClient.getInstances(SERVICE_NAME);  
        for (ServiceInstance instance : instances) {  
            InstanceInfo instanceInfo = ((EurekaDiscoveryClient.EurekaServiceInstance) instance).getInstanceInfo();  
            TreeMap data = restTemplate.getForObject(instance.getUri().toString() + "/hikariCpStatsController/poolStats", TreeMap.class);  
            dataAll.put(instanceInfo.getInstanceId(), data);  
        }  
        return dataAll;  
    }  
  
    @GetMapping("poolStats")  
    public TreeMap<String, Object> poolStats() {  
        MetricRegistry metricRegistry = null;  
        if (dataSource instanceof HikariDataSource) {  
            metricRegistry = (MetricRegistry) ((HikariDataSource) dataSource).getMetricRegistry();  
        }  
        if (metricRegistry == null)  
            return null;  
  
        TreeMap<String, Object> data = new TreeMap<>();  
  
        SortedMap<String, Gauge> gauges = metricRegistry.getGauges();  
        for (Map.Entry<String, Gauge> gaugeEntry : gauges.entrySet()) {  
            String key = gaugeEntry.getKey();  
            Gauge value = gaugeEntry.getValue();  
            data.put(key, value.getValue());  
  
        }  
        SortedMap<String, Timer> timers = metricRegistry.getTimers();  
        for (Map.Entry<String, Timer> timerEntry : timers.entrySet()) {  
            String key = timerEntry.getKey();  
            Timer value = timerEntry.getValue();  
            data.put(key, "获取连接时99%线程等待的纳秒=" + value.getSnapshot().get99thPercentile());  
        }  
        SortedMap<String, Meter> meters = metricRegistry.getMeters();  
        for (Map.Entry<String, Meter> meterEntry : meters.entrySet()) {  
            String key = meterEntry.getKey();  
            Meter value = meterEntry.getValue();  
            data.put(key, "count=" + value.getCount());  
        }  
        SortedMap<String, Histogram> histograms = metricRegistry.getHistograms();  
        for (Map.Entry<String, Histogram> histogramEntry : histograms.entrySet()) {  
            String key = histogramEntry.getKey();  
            Histogram value = histogramEntry.getValue();  
            data.put(key, "99%连接线程使用的毫秒=" + value.getSnapshot().get99thPercentile());  
        }  
        return data;  
    }  
}  

在此大功告成

参考// see detail https://github.com/brettwooldridge/HikariCP/wiki/Dropwizard-Metrics