Hikaricp连接池问题

HiKari源于日语“光”的意思,HiKariCP顾名思义就是 和光速一样快,HiKariCP是数据库连接池的一个后起之秀,号称性能最好,稳定性也不错,完美地PK掉其他连接池。这里提供一篇文章介绍主流Java数据库连接池比较及前瞻,文中重点介绍了当前主流开源数据库连接池(比如C3P0、DBCP、Tomcat Jdbc Pool、Druid和Hikaricp)的性能分析和功能比较,有一定的参考价值。

       回到本文正题,近期在计费生产系统上遇到一个很头疼的问题——Hikaricp连接池获取不到连接数而连接不到数据库,导致请求失败。每10笔交易会出现2笔,具体异常如下:

Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 932347ms.

at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:555) ~[HikariCP-2.4.7.jar:?]

at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:188) ~[HikariCP-2.4.7.jar:?]

at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:147) ~[HikariCP-2.4.7.jar:?]

at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:99) ~[HikariCP-2.4.7.jar:?]

at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) ~[spring-jdbc-4.3.5.RELEASE.jar:4.3.5.RELEASE]

at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) ~[spring-jdbc-4.3.5.RELEASE.jar:4.3.5.RELEASE]

at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:82) ~[mybatis-spring-1.2.3.jar:1.2.3]

at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:68) ~[mybatis-spring-1.2.3.jar:1.2.3]

at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:315) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:75) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:61) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:303) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:154) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:102) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:82) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120) ~[mybatis-3.3.0.jar:3.3.0]

at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113) ~[mybatis-3.3.0.jar:3.3.0]

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_79]

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_79]

at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_79]

at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:386) ~[mybatis-spring-1.2.3.jar:1.2.3]

... 26 more

问题分析:

1、异常抛出时间每次都是在15分30秒左右,但该系统的并行环境并没有此异常,生产环境的差异只是数据库部署在不同的主机上;

2、访问数据库命令的网络耗时正常,数据库端收到连接请求,且该时段数据库连接数并没有耗尽;

3、数据库管理员在异常时间段查询得知,不存在慢sql语句,不存在不合理设置索引导致此异常。

继续分析,只能从Hikaricp的配置着手:以下是出异常的数据源配置 

自此附上hikarecp各个配置的中文解释:hikariCP连接池配置

<bean id="dataSourcePubdba" class="com.zaxxer.hikari.HikariDataSource">

     <property name="driverClassName" value="${datasource.driver}">

     <property name="jdbcUrl" value="${datasource.jdbcUrl}">

     <property name="username" value="${datasource.user}">

     <property name="password" value="${datasource.pass.encrypt}">

     <property name="connectionTimeout" value="30000" />

    <property name="idleTimeout" value="60000" />

     <property name="maxLifetime" value="1800000" />

     <property name="maximumPoolSize" value="65" />

</bean>

后四个重要参数的解释:

    1)connectionTimeout:等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒 

    2)idleTimeout:此属性控制允许连接在池中闲置的最长时间,此设置仅适用于minimumIdle设置为小于maximumPoolSize的情况 默认:600000(10minutes)

   2)maxLifetime:一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒

3)maximumPoolSize:连接池中允许的最大连接数(包括空闲和正在使用的连接)。缺省值:10;

综合以上分析:connectionTimeout采用默认值30s,应该不会有太大问题。maximumPoolSize根据业务量的设置,不会有太大问题。maxLifetime如果过长,且idleTimeout没有时间限制时,会导致连接数很大,空闲连接一直得不到释放,严重挤占资源,容易引起连接数不够的问题。特别是maxLifetime如果大于数据库超时时长,就会抛出数据库连接异常,这也是本次生产问题所在:maxLifetime设置成30分钟,超过了数据库连接时长15分钟,connectionTimeout为30秒,所以每次异常都是在15分30秒抛出,数据库端已经收到Hikaricp连接请求,但是因网络问题等因素,到达超时时长而没有获取到连接。idleTimeout只有在minimumIdle设置为小于maximumPoolSize的情况下才生效,而我没有设置最小空闲连接数minimumIdle的值,minimumIdle默认是等于maximumPoolSize,此时idleTimeout不受限,空闲连接一直没有得到回收,出于系统优化以及并发稳定性考虑,应该增加此配置。

优化后的配置:

<bean id="dataSourceTxndba" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close" >//对象销毁前调用了close函数,这是必须的,否则对象离开后,数据库资源还可用

       <property name="driverClassName" value="${datasource.driver}"></property>

       <property name="jdbcUrl" value="${datasource.jdbcUrl2}"></property>

       <property name="username" value="${datasource.user2}"></property>

       <property name="password" value="${datasource.pass2.encrypt}"></property>

       <property name="connectionTimeout" value="30000" />

       <property name="idleTimeout" value="60000" />

       <property name="maxLifetime" value="600000" />

       <property name="minimumIdle" value="10" />

       <property name="maximumPoolSize" value="65" />

       <property name="poolName" value="TxnDatabasePool" />

       <property name="leakDetectionThreshold" value="5000"/>

</bean>

相比较之前的配置,优化点如下:

 1、增加数据连接关闭方法,当从dataSource获取的连接使用完成后,调用close方法,以避免数据源对象任然可用,造成连接泄露

 2、增加最小空闲连接数minimumIdle,根据业务场景,设置为10,小于maximumPoolSize值

3、连接空闲时间idleTimeout生效,根据业务请求重发频率为40多秒,值可设为1分钟,减少空闲连接占用,尽快释放数据库连接

4、连接生命周期maxLifetime值设为10分钟,低于数据库超时时长,尽快释放数据库无效连接

5、增加连接池的用户定义名称

6、开启连接监测泄露leakDetectionThreshold方法,此属性控制在记录消息之前连接可能离开池的时间量,表明可能的连接泄漏。值代表连接被占用的泄露时间最低可接受值为5秒,不过此值的设定需要根据场景多次调试,如果真实泄露时间小幅度超过5秒,会引起warning,但不一定会导出数据不能入库,因为该方法只是检查,只有到达idleTimeout ,才会强制执行关闭连接。

运行结果:

 使用该配置,目前系统暂未发生数据库连接异常现象,后续还会继续跟踪,以期获得最优配置。

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
对于HikariCP连接池,动态密码可以通过以下步骤实现: 1. 首先,添加HikariCP和MyBatis-Plus的依赖到你的项目中。 2. 在配置文件(比如application.properties或application.yml)中配置HikariCP连接池的相关参数,比如数据库URL、用户名、初始密码等。将密码字段设置为占位符,例如:`spring.datasource.password=placeholder`. 3. 在项目启动时,通过编程方式获取到真实的密码,并将其设置到HikariCP连接池的配置中。 4. 可以使用Spring的事件机制,在应用启动时监听事件,在事件监听器中获取真实密码并设置到HikariCP连接池配置中。 下面是一个示例代码: ```java @Component public class HikariPasswordListener implements ApplicationListener<ApplicationReadyEvent> { @Autowired private HikariDataSource dataSource; @Override public void onApplicationEvent(ApplicationReadyEvent event) { // 获取真实密码的逻辑,可以从配置文件、数据库或其他安全存储中获取 String realPassword = "your_real_password"; // 设置真实密码到HikariCP连接池配置中 dataSource.setPassword(realPassword); } } ``` 在上述示例中,我们创建了一个监听器 `HikariPasswordListener`,并在应用启动时监听 `ApplicationReadyEvent` 事件。在监听器中,我们注入了 `HikariDataSource` 对象,并获取真实的密码。然后将真实密码设置到 `HikariDataSource` 对象的密码字段中。 这样,HikariCP连接池就可以使用动态密码了。注意,示例中使用了Spring的事件机制,如果你的项目没有使用Spring,可以考虑使用其他适合的方式来设置真实密码到HikariCP连接池配置中。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值