使用HikariCP连接池常用配置讲解及注意事项
Posted Aubrey-J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用HikariCP连接池常用配置讲解及注意事项相关的知识,希望对你有一定的参考价值。
使用HikariCP连接池常用配置讲解及注意事项
常遇到的几种错误
Possibly consider using a shorter maxLifetime value
SpringCloud 中使用HikariPool 报错Possibly consider using a shorter maxLifetime value
HikariPool-1 - Failed to validate connection
com.mysql.cj.jdbc.ConnectionImpl@115a8473 (No operations allowed after connection closed.).
Possibly consider using a shorter maxLifetime value
Connection is not available, request timed out after xxxxxms
Connection is not available, request timed out after 59089ms
No operations allowed after connection closed
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed
对于以上几种错误,我经过查阅,众说纷纭,大部分解决了的都是(并不是长久之计)
- 按照提示缩短了maxLifetime到5分钟
- 增加测试查询语句connection-test-query
来解决问题,并没有实际的分析问题根源或者优化其他配置项,经过查询相关文档、尝试、观察、测试,得出以下结论,给大家讲解,急于处理问题的可以参考下面的配置进行调整,注意标明的注释,可做适当调整,后文我将对常用的配置项进行讲解
常见配置及注释说明,可以使用并根据说明调整
spring:
datasource:
hikari: # 时间单位均为ms
minimum-idle: 5 # 建议不设置,但如使用idle-timeout,该值需要小于maximum-pool-size
maximum-pool-size: 10 # hikari做过测试根据CPU计算最优最大连接池,如下
# connections = ((cpu_core_count * 2) + effective_spindle_count)
# 如4-Core i7,公式为9 = ((4 * 2) + 1),最后一个是有效的主核心数
auto-commit: true # 默认
idle-timeout: 300000 # 该值建议小于max-lifetime
max-lifetime: 600000 # 该值建议小于数据库的连接关闭等待时间,详细的看下面分析
connection-timeout: 30000 # 默认30s,连接超时会报异常
# Connection is not avaitabte, request timed out after 59089ms
validation-timeout: 5000 # 支持JDBC4的是isValid超时时间,不支持的是testQuery超时时间
connection-test-query: 'SELECT 1' # 支持JDBC4的不建议使用,因为JDBC4的isValid方法效率更高
详细分析
首先确认网络问题
将数据库连接到本地(注意需要保持数据库的配置和线上一致,否则没有可比性,无法得出结论),并进行长时间运行测试,如果没有问题,则是由于网络原因链接超时,造成了关闭的连接本地调用失败、或创建连接超时无法使用,这种情况优化网络配置、增加带宽、将服务和数据库部署在同一网络下等方案即可
maximum-pool-size建议值
hikari做过测试根据CPU计算最优最大连接池,详细的可以看链接的官方讲解,比较长,总结如下
- connections = ((cpu_core_count * 2) + effective_spindle_count)
- 如4-Core i7,公式为9 = ((4 * 2) + 1),最后一个是有效的主核心数
minimum-idle
该值HikariCP建议不设置,就使用默认的,也就是同maximum-pool-size一边大,但是实际应用中可能需要保留少一些,随着业务的增加变到maximum-pool-size,而不是长期占用maximum-pool-size这么多的连接数。
- 所以可以设置一个比较小的、或者常态化下使用的连接量即可,建议5-10即可,不可大于maximum-pool-size
idle-timeout
连接允许在池中闲置的最长时间,默认为600000,即10分钟。只有当minimum-idle小于maximum-pool-size时,这个参数才生效,当空闲连接数超过minimum-idle,而且连接空闲时间超过idle-timeout,则会被移除。
- 设置时,该值建议小于max-lifetime
max-lifetime
官方建议是比数据库的wait_timeout小几秒,但是MySQL默认一般都是8小时,28800s(数据库单位是s秒),如下图
# 查看数据库的wait_timeout、interactive_timeout
show variables like '%timeout%';
所以设置有几种方式
- 根据数据的超时时长,减少一些时间,然后变为毫秒数,配置该值
- 使用默认值
- 使用小于默认值的,如5分钟、10分钟、15分钟等
但是该值一定要大于idle-timeout。
connection-timeout
连接池等待连接的最大毫秒数,默认为30000ms,也就是30s,允许最小时间是250毫秒,如果小于250毫秒,则被重置回30秒。
- 根据网络情况,处理器性能,服务可接受超时时长,配置合理的值即可
- 一般设置短一点,提高程序的响应速度,但是要大于网络的平均响应时长,否则全会连接超时
- 小于idle-timeout
# 出现这种错误一般就是连接超时了,检查网络响应时间、网络状态等
Connection is not avaitabte, request timed out after 59089ms
validation-timeout
支持JDBC4的驱动,是调用isValid验证连接池中连接有效性的超时时间
不支持JDBC4的驱动,是调用testQuery的超时时间
- 该值尽量小一些,使用默认值即可,但是要小于connection-timeout
connection-test-query
支持JDBC4的不建议使用,因为JDBC4的驱动有isValid方法,是通过发送数据包验证连接,效率更高
不支持JDBC4的驱动,是执行该配置的SQL,比较重,效率不好
- 如果没有配置该值,而且驱动不支持JDBC4,会有错误提示,所以没有配置,也没有提示isValid相关错误,即表示支持
为啥HikariCP被号称为性能最好的Java数据库连接池,如何配置使用
HiKariCP是数据库连接池的一个后起之秀,号称性能最好,可以完美地PK掉其他连接池。为何要使用HiKariCP?这要先从BoneCP说起:
什么?不是有C3P0/DBCP这些成熟的数据库连接池吗?一直用的好好的,为什么又搞出一个BoneCP来?因为,传说中BoneCP在快速这个特点上做到了极致,官方数据是C3P0等的25倍左右。不相信?其实我也不怎么信。可是,有图有真相啊(图片来自BoneCP官网:http://jolbox.com/benchmarks.html):
而且,网上对于BoneCP是好评如潮啊,推荐的文章一搜一大堆。
然而,上Maven Repository网站(http://mvnrepository.com/artifact/com.jolbox/bonecp)查找有没有最新版本的时候,你会发现最新的是2013年10月份的(这么久没新版本出来了?)。于是,再去BoneCP的Githut(https://github.com/wwadge/bonecp)上看看最近有没有提交代码。却发现,BoneCP的作者对于这个项目貌似已经心灰意冷,说是要让步给HikariCP了(有图有真相):
……什么?又来一个CP?……什么是Hikari?
Hikari来自日文,是“光”(阳光的光,不是光秃秃的光)的意思。作者估计是为了借助这个词来暗示这个CP速度飞快。不知作者是不是日本人,不过日本也有很多优秀的码农,听说比特币据说日本人搞出来的。。。
这个产品的口号是“快速、简单、可靠”。实际情况跟这个口号真的匹配吗?又是有图有真相(Benchmarks又来了):
这个图,也间接地、再一次地证明了boneCP比c3p0强大很多,当然,跟“光”比起来,又弱了不少啊。
那么,这么好的P是怎么做到的呢?官网详细地说明了HikariCP所做的一些优化,总结如下:
字节码精简:优化代码,直到编译后的字节码最少,这样,CPU缓存可以加载更多的程序代码;
优化代理和拦截器:减少代码,例如HikariCP的Statement proxy只有100行代码,只有BoneCP的十分之一;
自定义数组类型(FastStatementList)代替ArrayList:避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描;
自定义集合类型(ConcurrentBag):提高并发读写的效率;
其他针对BoneCP缺陷的优化,比如对于耗时超过一个CPU时间片的方法调用的研究(但没说具体怎么优化)。
很多优化的对比都是针对BoneCP的……哈哈。
(参考文章:https://github.com/brettwooldridge/HikariCP/wiki/Down-the-Rabbit-Hole)
几个连接池的代码量对比(代码量越少,一般意味着执行效率越高、发生bug的可能性越低):
可是,“黄婆卖瓜,自催自擂”这个俗语日本人也是懂得,于是,用户的好评如潮也是有图有真相:
还有第三方关于速度的测试:
也许你会说,速度高,如果不稳定也是硬伤啊。于是,关于稳定性的图也来了:
另外,关于可靠性方面,也是有实验和数据支持的。对于数据库连接中断的情况,通过测试getConnection(),各种CP的不相同处理方法如下:
(所有CP都配置了跟connectionTimeout类似的参数为5秒钟)
HikariCP:等待5秒钟后,如果连接还是没有恢复,则抛出一个SQLExceptions 异常;后续的getConnection()也是一样处理;
C3P0:完全没有反应,没有提示,也不会在“CheckoutTimeout”配置的时长超时后有任何通知给调用者;然后等待2分钟后终于醒来了,返回一个error;
Tomcat:返回一个connection,然后……调用者如果利用这个无效的connection执行SQL语句……结果可想而知;大约55秒之后终于醒来了,这时候的getConnection()终于可以返回一个error,但没有等待参数配置的5秒钟,而是立即返回error;
BoneCP:跟Tomcat的处理方法一样;也是大约55秒之后才醒来,有了正常的反应,并且终于会等待5秒钟之后返回error了;
可见,HikariCP的处理方式是最合理的。根据这个测试结果,对于各个CP处理数据库中断的情况,评分如下:
参考文章:https://github.com/brettwooldridge/HikariCP/wiki/Bad-Behavior:-Handling-Database-Down
说得这么好,用起来会不会很麻烦啊,会不会有很多参数要配置才能有这样的效果啊?答案是:不会。
如果之前用的是BoneCP配置的数据源,那么,就简单了,只需要把dataSource换一下,稍微调整一下参数就行了:
BoneCP的数据源配置:
<!--BoneCpDatasource-->
<beanid="dataSourceBoneCp"class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close">
<propertyname="driverClass"value="$db.driverClass"/>
<propertyname="jdbcUrl"value="$db.url"/>
<propertyname="username"value="$db.username"/>
<propertyname="password"value="$db.password"/>
<propertyname="idleConnectionTestPeriodInMinutes"value="2"/>
<propertyname="idleMaxAgeInMinutes"value="2"/>
<propertyname="maxConnectionsPerPartition"value="2"/>
<propertyname="minConnectionsPerPartition"value="0"/>
<propertyname="partitionCount"value="2"/>
<propertyname="acquireIncrement"value="1"/>
<propertyname="statementsCacheSize"value="100"/>
<propertyname="lazyInit"value="true"/>
<propertyname="maxConnectionAgeInSeconds"value="20"/>
<propertyname="defaultReadOnly"value="true"/>
</bean>
HiKariCP的数据源配置:
<!--HikariDatasource-->
<beanid="dataSourceHikari"class="com.zaxxer.hikari.HikariDataSource"destroy-method="shutdown">
<!--<propertyname="driverClassName"value="$db.driverClass"/>--><!--无需指定,除非系统无法自动识别-->
<propertyname="jdbcUrl"value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8"/>
<propertyname="username"value="$db.username"/>
<propertyname="password"value="$db.password"/>
<!--连接只读数据库时配置为true,保证安全-->
<propertyname="readOnly"value="false"/>
<!--等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException,缺省:30秒-->
<propertyname="connectionTimeout"value="30000"/>
<!--一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟-->
<propertyname="idleTimeout"value="600000"/>
<!--一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒,参考MySQLwait_timeout参数(showvariableslike'%timeout%';)-->
<propertyname="maxLifetime"value="1800000"/>
<!--连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count*2)+effective_spindle_count)-->
<propertyname="maximumPoolSize"value="15"/>
</bean>
其中,很多配置都使用缺省值就行了,除了maxLifetime和maximumPoolSize要注意自己计算一下。
其他的配置(sqlSessionFactory、MyBatis MapperScannerConfigurer、transactionManager等)统统不用变。
其他关于Datasource配置参数的建议:
Configure your HikariCPidleTimeoutandmaxLifeTimesettings to be one minute less than thewait_timeoutof MySQL. 参考技术A 为何要使用HiKariCP?这要先从BoneCP说起:
什么?不是有C3P0/DBCP这些成熟的数据库连接池吗?一直用的好好的,为什么又搞出一个BoneCP来?因为,传说中BoneCP在快速这个特点上做到了极致,官方数据是C3P0等的25倍左右。不相信?其实我也不怎么信。可是,有图有真相啊(图片来自BoneCP官网:
关于可靠性方面,也是有实验和数据支持的。对于数据库连接中断的情况,通过测试getConnection(),各种CP的不相同处理方法如下:
(所有CP都配置了跟connectionTimeout类似的参数为5秒钟)
HikariCP:等待5秒钟后,如果连接还是没有恢复,则抛出一个SQLExceptions 异常;后续的getConnection()也是一样处理;
C3P0:完全没有反应,没有提示,也不会在“CheckoutTimeout”配置的时长超时后有任何通知给调用者;然后等待2分钟后终于醒来了,返回一个error;
Tomcat:返回一个connection,然后……调用者如果利用这个无效的connection执行SQL语句……结果可想而知;大约55秒之后终于醒来了,这时候的getConnection()终于可以返回一个error,但没有等待参数配置的5秒钟,而是立即返回error;
BoneCP:跟Tomcat的处理方法一样;也是大约55秒之后才醒来,有了正常的反应,并且终于会等待5秒钟之后返回error了;
上述都是在网上找得到的,你直接搜关键字就可以看到的。
以上是关于使用HikariCP连接池常用配置讲解及注意事项的主要内容,如果未能解决你的问题,请参考以下文章
为啥HikariCP被号称为性能最好的Java数据库连接池,如何配置使用
为啥HikariCP被号称为性能最好的Java数据库连接池,如何配置使用