关于SpringBoot中使用ShardingSphere(ShardingJdbc)+Hikari数据库连接池后Prometheus无法获取到hikaricp监控数据的解决方案

本文介绍如何在使用ShardingSphere分库分表中间件时,通过自定义配置实现HikariCP连接池的Prometheus监控,提供详细的监控指标解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot2.X版本后使用Hikari作为数据库的默认的连接池。

Spring.datasource的默认配置中使用了自动配置的方式来绑定MetricsRegistry,

在spring-boot-actuator-autoconfigure包中org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration类中默认包含了有关于HikariDataSoucre的Metrics监控的绑定逻辑

而HikariCP也提供了有关使用Prometheus监控的具体实现

当使用使用spring.datasource的基本配置时,springboot的自动配置和hikari中的监控逻辑二者结合后,有关prometheus的metrice监控数据就会呈现出来

application.properties中配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    url: ${url}
    username: ${username}
    password: ${password}
    hikari:
      pool-name: HikariPool-1        
      minimum-idle: 10           
      maximum-pool-size: 20      
      idle-timeout: 500000        
      max-lifetime: 540000        
      connection-timeout: 60000   
      connection-test-query: SELECT 1

当我们开启了prometheus的端点监控后http://IP:PORT/actuator/prometheus便可以查看到关于hikaricp相关的监控数据,同时利用prometheus实时抓取监控数据用于图标呈现

# HELP hikaricp_connections_max Max connections
# TYPE hikaricp_connections_max gauge
hikaricp_connections_max{pool="HikariPool-1",} 50.0
# HELP hikaricp_connections_pending Pending threads
# TYPE hikaricp_connections_pending gauge
hikaricp_connections_pending{pool="HikariPool-1",} 0.0
# HELP hikaricp_connections_timeout_total Connection timeout total count
# TYPE hikaricp_connections_timeout_total counter
hikaricp_connections_timeout_total{pool="HikariPool-1",} 0.0
# HELP hikaricp_connections_acquire_seconds Connection acquire time
# TYPE hikaricp_connections_acquire_seconds summary
hikaricp_connections_acquire_seconds_count{pool="HikariPool-1",} 1.0
hikaricp_connections_acquire_seconds_sum{pool="HikariPool-1",} 7.39E-5
# HELP hikaricp_connections_acquire_seconds_max Connection acquire time
# TYPE hikaricp_connections_acquire_seconds_max gauge
hikaricp_connections_acquire_seconds_max{pool="HikariPool-1",} 7.39E-5
# HELP hikaricp_connections_min Min connections
# TYPE hikaricp_connections_min gauge
hikaricp_connections_min{pool="HikariPool-1",} 3.0
# HELP hikaricp_connections_usage_seconds Connection usage time
# TYPE hikaricp_connections_usage_seconds summary
hikaricp_connections_usage_seconds_count{pool="HikariPool-1",} 1.0
hikaricp_connections_usage_seconds_sum{pool="HikariPool-1",} 0.025
# HELP hikaricp_connections_usage_seconds_max Connection usage time
# TYPE hikaricp_connections_usage_seconds_max gauge
hikaricp_connections_usage_seconds_max{pool="HikariPool-1",} 0.025
# HELP hikaricp_connections_creation_seconds_max Connection creation time
# TYPE hikaricp_connections_creation_seconds_max gauge
hikaricp_connections_creation_seconds_max{pool="HikariPool-1",} 0.094
# HELP hikaricp_connections_creation_seconds Connection creation time
# TYPE hikaricp_connections_creation_seconds summary
hikaricp_connections_creation_seconds_count{pool="HikariPool-1",} 2.0
hikaricp_connections_creation_seconds_sum{pool="HikariPool-1",} 0.178
# HELP hikaricp_connections_active Active connections
# TYPE hikaricp_connections_active gauge
hikaricp_connections_active{pool="HikariPool-1",} 0.0
# HELP hikaricp_connections Total connections
# TYPE hikaricp_connections gauge
hikaricp_connections{pool="HikariPool-1",} 3.0
# HELP hikaricp_connections_idle Idle connections
# TYPE hikaricp_connections_idle gauge
hikaricp_connections_idle{pool="HikariPool-1",} 3.0

但是,当我们使用了ShardingSphere作为分库分表中间件来使用以后,因为由于自动配置中使用的DataSource由HikariDataSource变为了ShardingDataSource,所以无法完成对HikariMetricsRegistry的绑定操作,因此使用了Sharding后无法再从/actuator/prometheus中看到关于hikaricp有关的数据。

那么如何解决这个问题呢,我们可以模仿这个DataSourcePoolMetricsAutoConfiguration的逻辑,为Sharding内的dataSources进行循环绑定。

我们知道,Sharding的自动配置逻辑中,org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration,将Sharding配置的多数据库连接放到了一个dataSourceMap中。因此我们绑定MetricsRegistry时也就是需要获取Sharing中的dataSourceMap中的数据来分别注册。通常我们会如下配置shardingsphere定义2个数据源.

application.properties中配置

spring:
  shardingsphere:
    datasource:
      names: ds0, ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbcUrl: ${url}
        username: ${username}
        password: ${password}
        pool-name: HikariPool-1        
        minimum-idle: 10            
        maximum-pool-size: 20       
        idle-timeout: 500000       
        max-lifetime: 540000    
        connection-timeout: 60000  
        connection-test-query: SELECT 1
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbcUrl: ${url}
        username: ${username}
        password: ${password}
        pool-name: HikariPool-2      
        minimum-idle: 10           
        maximum-pool-size: 20      
        idle-timeout: 500000      
        max-lifetime: 540000      
        connection-timeout: 60000 
        connection-test-query: SELECT 1        

同时我们模仿DataSourceMetricsConfiguration,编写一个ShardingDataSourceMetricsConfiguration,源码如下

import java.util.Collection;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.log.LogMessage;

import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory;

import io.micrometer.core.instrument.MeterRegistry;

@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter({ MetricsAutoConfiguration.class, DataSourceAutoConfiguration.class,
		SimpleMetricsExportAutoConfiguration.class })
@ConditionalOnClass({ DataSource.class, MeterRegistry.class })
@ConditionalOnBean({ DataSource.class, MeterRegistry.class })
public class ShardingDataSourcePoolMetricsAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ShardingDataSource.class, HikariDataSource.class})
	static class ShardingDataSourceMetricsConfiguration {

		private static final Log logger = LogFactory.getLog(ShardingDataSourceMetricsConfiguration.class);

		private final MeterRegistry registry;

		ShardingDataSourceMetricsConfiguration(MeterRegistry registry) {
			this.registry = registry;
		}

		@Autowired
		void bindMetricsRegistryToHikariDataSources(Collection<DataSource> dataSources) {
			for (DataSource dataSource : dataSources) {
				ShardingDataSource shardingDataSource = DataSourceUnwrapper.unwrap(dataSource, ShardingDataSource.class);
				Collection<DataSource> shardDataSources = shardingDataSource.getDataSourceMap().values();
				for (DataSource ds : shardDataSources) {
					HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(ds, HikariDataSource.class);
					if (hikariDataSource != null) {
						bindMetricsRegistryToHikariDataSource(hikariDataSource);
					}
				}
			}
		}

		private void bindMetricsRegistryToHikariDataSource(HikariDataSource hikari) {
			if (hikari.getMetricRegistry() == null && hikari.getMetricsTrackerFactory() == null) {
				try {
					hikari.setMetricsTrackerFactory(new MicrometerMetricsTrackerFactory(this.registry));
				}
				catch (Exception ex) {
					logger.warn(LogMessage.format("Failed to bind Hikari metrics: %s", ex.getMessage()));
				}
			}
		}

	}
}

重点就是在这里,我们知道ShardingDataSource中包含了具体数据源连接池,只要解析出hikariDataSource然后分别绑定进去,可以分别获取到监控数据了。

当我们再次访问http://IP:PORT/actuator/prometheus,我们就可以看到出现了设置的2个数据源连接池的监控数据。

 

附带指标监控解释

指标1:hikaricp_pending_threads
hikaricp_pending_threads 表示当前排队获取连接的线程数,Guage类型。该指标持续飙高,说明DB连接池中基本已无空闲连接。
指标2:hikaricp_connection_acquired_nanos
hikaricp_connection_acquired_nanos表示连接获取的等待时间,一般取99位数,Summary类型
指标3:hikaricp_idle_connections
hikaricp_idle_connections表示当前空闲连接数,Gauge类型。HikariCP是可以配置最小空闲连接数的,当此指标长期比较高(等于最大连接数)时,可以适当减小配置项中最小连接数。
指标4:hikaricp_active_connections
hikaricp_active_connections表示当前正在使用的连接数,Gauge类型。如果此指标长期在设置的最大连接数上下波动时,或者长期保持在最大线程数时,可以考虑增大最大连接数。
指标5:hikaricp_connection_usage_millis
hikaricp_connection_usage_millis表示连接被复用的间隔时长,一般取99位数,Summary类型。该配置的意义在于表明连接池中的一个连接从被返回连接池到再被复用的时间间隔,对于使用较少的数据源,此指标可能会达到秒级,可以结合流量高峰期的此项指标与激活连接数指标来确定是否需要减小最小连接数,若高峰也是秒级,说明对比数据源使用不频繁,可考虑减小连接数。
指标6:hikaricp_connection_timeout_total
hikaricp_connection_timeout_total表示每分钟超时连接数,Counter类型。主要用来反映连接池中总共超时的连接数量,此处的超时指的是连接创建超时。经常连接创建超时,一个排查方向是和运维配合检查下网络是否正常。
指标7:hikaricp_connection_creation_millis
hikaricp_connection_creation_millis表示连接创建成功的耗时,一般取99位数,Summary类型。该配置的意义在于表明创建一个连接的耗时,主要反映当前机器到数据库的网络情况,在IDC意义不大,除非是网络抖动或者机房间通讯中断才会有异常波动。

 

 

<think>好的,我现在需要回答用户关于Java数据库连接池的问题。首先,我得确保自己理解连接池的基本概念和作用。数据库连接池是一种管理数据库连接的技术,用来重用连接,减少频繁创建和关闭连接的开销,提高性能。接下来,我需要考虑用户可能的背景,他们可能是Java开发者,对数据库操作有一定了解,但可能不清楚连接池的具体实现和优势。 接下来,我应该结构清晰地分步骤介绍。首先解释什么是连接池,为什么需要它。然后,可以对比传统连接方式的不足,比如每次操作都新建连接,导致资源消耗大,响应慢。接着,说明连接池的工作原理,比如预先创建一定数量的连接,使用时取出,用完后归还,而不是关闭。 然后,需要提到常见的Java连接池实现,比如HikariCP、Apache DBCP、C3P0等,比较它们的优缺点,帮助用户选择合适的库。HikariCP性能好,推荐使用;DBCP和C3P0可能较旧或效率稍低。这部分需要准确,避免错误信息。 还要说明连接池的关键配置参数,比如最小连接数、最大连接数、超时时间等,这些参数如何影响应用性能。比如,设置过大的最大连接数可能导致资源浪费,过小则可能无法处理高并发。 此外,需要给出一个简单的代码示例,展示如何使用HikariCP配置连接池,包括数据源设置、获取连接、执行查询等步骤。确保代码正确,语法无误,用户可以直接参考。 还要注意用户可能遇到的问题,比如连接泄漏,如何通过配置检测和避免。比如设置泄漏检测参数,或者使用try-with-resources确保连接关闭。 最后,总结连接池的优势,比如提升性能、资源复用、管理连接生命周期等,并推荐最佳实践,如选择合适的连接池实现,合理配置参数,监控连接池状态等。 在整理这些点时,要遵循用户的系统级指令,数学公式用$...$,独立公式用$$...$$,但这个问题可能涉及较少数学内容。不过如果有涉及性能指标的计算,可能需要用LaTeX表达,比如连接数计算公式,但暂时可能不需要。主要确保回答结构清晰,用中文,分步骤,正确可靠。同时检查是否有错误,比如HikariCP是否真的是最快,DBCP和C3P0的现状是否准确,避免过时信息。可能需要确认最新的资料,确保推荐和比较的准确性。</think>以下是关于Java数据库连接池的详细介绍,分步骤说明其核心概念和实现原理: --- ### 一、什么是数据库连接池数据库连接池(Database Connection Pool)是一种**复用和管理数据库连接**的技术。其核心思想是预先创建一定数量的数据库连接并缓存起来,当应用程序需要操作数据库时,直接从池中获取连接,使用完毕后归还而非关闭。 $$ \text{连接池大小} = \text{最小空闲连接数} \leq \text{活跃连接数} \leq \text{最大连接数} $$ --- ### 二、为什么需要连接池? 1. **传统方式的问题** - 每次操作都新建连接:消耗资源(如TCP握手、身份验证)。 - 频繁关闭连接:导致数据库服务端压力增大。 - 高并发场景下:连接数激增可能触发数据库的最大连接限制。 2. **连接池的优势** - **性能提升**:复用连接,减少创建/销毁开销。 - **资源可控**:通过配置限制最大连接数,避免数据库过载。 - **连接管理**:支持超时回收、泄漏检测等机制。 --- ### 三、常见的Java连接池实现 | 名称 | 特点 | |-------------|----------------------------------------------------------------------| | **HikariCP** | 高性能,轻量级(如$2.7 \text{MB}$),Spring Boot默认集成。 | | **DBCP** | Apache项目,稳定但性能一般。 | | **C3P0** | 历史较久,存在资源泄漏风险,逐渐被淘汰。 | --- ### 四、连接池的关键配置参数 1. **基础配置** - `minimumIdle`: 最小空闲连接数(默认等于`maximumPoolSize`)。 - `maximumPoolSize`: 最大连接数(建议根据数据库负载调整)。 - `connectionTimeout`: 获取连接的超时时间(如$3000\text{ms}$)。 2. **高级功能** - `idleTimeout`: 空闲连接超时回收时间。 - `leakDetectionThreshold`: 连接泄漏检测阈值(如$60000\text{ms}$)。 --- ### 五、代码示例(HikariCP) ```java // 1. 配置数据HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb"); config.setUsername("user"); config.setPassword("password"); config.setMaximumPoolSize(10); // 2. 创建连接池 HikariDataSource dataSource = new HikariDataSource(config); // 3. 获取连接并执行操作 try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement()) { ResultSet rs = stmt.executeQuery("SELECT * FROM users"); // 处理结果集... } ``` --- ### 六、最佳实践 1. **选择合适的实现**:优先使用HikariCP。 2. **合理配置参数**:避免过大或过小的连接数。 3. **监控连接池状态**:通过JMX或监控工具(如Prometheus)实时观察活跃连接数、空闲连接数等指标。 --- 通过连接池技术,Java应用程序能够更高效、安全地管理数据库连接,显著提升系统性能和稳定性。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值