SpringBoot数据库连接池Hikari配置
SpringBoot数据库连接池Hikari配置
在项目中,一般情况下访问数据库,会创建一个连接,用完后就关闭它,对于简单的系统这样不会带来什么明显的性能上的开销。但是对于一个复杂的系统,频繁的建立、关闭连接,会极大的减低系统的性能,因为对于数据库连接的使用可能会成为系统性能的瓶颈。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。
SpringBoot默认使用Hikari
SpringBoot项目如果我们通过启动器starter使用JPA或者Mybatis,是默认会使用Hikari数据库连接池的,官方的介绍如下:
Connection to a Production Database
Production database connections can also be auto-configured by using a pooling
DataSource
. Spring Boot uses the following algorithm for choosing a specific implementation:
- We prefer HikariCP for its performance and concurrency. If HikariCP is available, we always choose it.
- Otherwise, if the Tomcat pooling
DataSource
is available, we use it.- Otherwise, if Commons DBCP2 is available, we use it.
- If none of HikariCP, Tomcat, and DBCP2 are available and if Oracle UCP is available, we use it.
If you use the
spring-boot-starter-jdbc
orspring-boot-starter-data-jpa
“starters”, you automatically get a dependency toHikariCP
.
spring-boot-starter-jdbc
Starter for using JDBC with the HikariCP connection pool
spring-boot-starter-jdbc依赖会自动使用HikariCP,在SpringBoot项目中如果我们通过mybatis-spring-boot-starter启动器使用mybatis连接数据库,可以看到spring-boot-starter-jdbc是编译依赖项。
如果我们通过spring-boot-starter-data-jpa启动器starter使用JPA连接数据库,可以看到spring-boot-starter-jdbc也是编译依赖项。所以SpringBoot项目我们通过spring-boot-starter-data-jpa使用JPA或者mybatis-spring-boot-starter使用Mybatis都是会默认自动使用Hikari数据库连接池。
Hikari常用配置
在SpringBoot项目中我们可以不配置Hikari的配置项,项目会使用默认的值启用HikariCP数据库连接池,我们也可以通过application.yml/application.properties文件设置HikariCP的配置项,常用的配置项如下:
# Hikari pool https://github.com/brettwooldridge/HikariCP
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
# 连接池中允许的最小连接数。缺省值:10
spring.datasource.hikari.minimum-idle=10
# 连接池中允许的最大连接数。缺省值:10
spring.datasource.hikari.maximum-pool-size=100
# 自动提交
spring.datasource.hikari.auto-commit=true
# 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟
spring.datasource.hikari.idle-timeout=30000
# 连接池名字
spring.datasource.hikari.pool-name=FlyduckHikariCP
# 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒
spring.datasource.hikari.max-lifetime=1800000
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
spring.datasource.hikari.connection-timeout=30000
# 数据库连接测试语句
spring.datasource.hikari.connection-test-query=SELECT 1
除了dadaSourceClassName/jdbcUrl、username、password这三个必须配置之外,HikariCP还有一些非必须配置,非必需配置包含的常用配置和非常用配置都是可选的。HikariCP 强烈反对向池中添加大量参数配置,这样会使代码复杂化,所以迫使用户必须考虑配置是否必须,这导致调整数据库连接池这项工作变得复杂。
Apache DBCP有超过40个池属性,但是估计实际生产中90%使用DBCP的应用部署并没有正确调整性能和可靠性。
1.常用配置
常用配置有 10个,我们一起看看它们都有哪些,都是做什么的,默认值是什么。
( 1 ) autoCommit
此属性控制从池返回的连接的默认自动提交事务行为。它是一个布尔值,默认值:true。
( 2 ) connectionTimeout
此属性控制客户端(即用户的程序)等待池中连接的最长毫秒数。如果在没有连接可用的情况下超过此时间,则将抛出SQLException异常。最低可接受的连接超时为250毫秒。
默认值:30000(30秒)。这是一个很重要的问题排查指标。
( 3 ) idleTimeout
此属性控制连接允许被闲置在池中的最大时间。此设置仅适用于 minimumIdle 定义为比 maximumPoolSize 小的时候。
一旦池到达minimumIdle连接的时候,空闲连接将不会
退役。连接是否空闲而退役的最大变化为+30秒,平均变化为+15秒。在此超时之前,连接永远不会因空闲状态而退役。值为0意味着空闲连接永远不会从池中删除即永不超时。
minimum允许的最小值为10000毫秒(10秒)。默认值:600000(10分钟)。
在繁忙的数据库连接池中,连接可能永远不会达到idleTimeout。
但是,许多防火墙和负载均衡器(通常位于应用程序和数据库之间)会占用套接字生存周期。通常,达到idleTimeout时,无论当前流量如何,都会切断连接。
HikariCP 设计之初就不支持空闲连接检测 test-while-idle,这是因为数据库管理员 DBA往往会默认设置数据库最长连接时间是60秒,test-while-idle会对数据库产生不必要的查询,
这样就有可能导致数据库空闲连接出现超时的问题。在HikariCP的旧版本中,maxLifetime由管家线程HouseKeeper强制执行,每30秒执行一次,因为wait_timeout减去30秒就是推荐的 maxLifetime。但是最新版本的HikariCP对每个连接connection进行专用计时器任务,提供了几十毫秒(在高负载下长达几秒)的时间间隔,此时maxLifetime被安全地设置
为wait_timeout减去5秒。如果连接退出,后台线程会执行添加操作,创建新的连接大约是5毫秒。如果maxLifetime是60秒,那么idleTimeout可以被设置为0。
( 4 ) maxLifetime
maxLifetime 属性用来控制池中连接的最大生命周期。使用中的连接永远不会退役,只有关闭后连接才会被移除。HikariCP 不会让所有的连接同时退役,而是巧妙地对每一个连接都设置了轻微的负衰减值,以避免池中的连接大规模消亡。
HikariCP作者强烈建议用户设置此值,并且它应比任何数据库或基础设施实施的连接时间限制短几秒。值0表示没有最大生存期(无限生存期),当然这取决于 idleTimeout 设置。默认值为1800000(30分钟)。
30分钟的默认超时是非常合理的,因为在应用程序与很多数据库之间,会有高可用代理、负载均衡、防火墙等,通常这些组件会自动且独立终止达到30分钟的连接。互联网上有大量关于数据库通信异常的问题,最终发现这些问题基本都是由这些组件引发的。另外,因为连接的建立通常需要几毫秒,由于一些方差因素的注人,所以使得退役和重新建立连接在应用程序级别实际上是不可测量的。当然,maxLifetime 作为数据库连接池的核心指标,很多情况下也是可以进行调整的。
有些使用 MySQL 的应用会报如下的错误:
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
1
这个问题分两种情况来看,是立即发生还是一段时间以后发生?如果是一段时间以后
发生,一般是因为数据库的wait_timeout小于HikariCP的maxLifetime值,此时可以将maxLifetime 设置缩短到 900 000毫秒(15分钟);当然更好的方法是,确定 MySQL 配置的wait_timeout值是什么,并将HikariCP 设置为比 maxLifetime 短几分钟。
与此类似,还有一个经典的Communications link failure问题也与这个参数密切相关,相关描述如下:
com.mysq1.jdbc.exceptions.jdbc4.communicationsException:Communications link failure
The last packet successfully received from the server was 13,529 milliseconds ago. The last packet sent successfully to the server was 13,529 milliseconds ago.
maxLifetime也是可以设置到15分钟或者比数据库超时时间短一些(比如MySQL的wait_timeout属性),这和minimumIdle和IdleTimeout这两个参数设置相关性不大,通过这个调整可以使 HikariCP 在数据库断掉连接之前先终止连接。如果要提高池中连接更替的速度,可以调低 maxLifetime的值(默认是30分钟),但是不建议设置到低于5分钟。
( 5 ) connectionTestQuery
如果驱动程序支持JDBC4,则建议不要设置此属性。这适用于不支持JDBC4的Connection.isValid()的“遗留”驱动程序API。这是一个检测查询,在数据库连接池给出连接之前进行查询,以验证与数据库的连接是否仍然存在且有效。同样,尝试运行数据库连接池并不配置该属性,如果你的驱动程序不支持JDBC4,那么HikariCP将报错。该属性默认值:无。
注意,如果你追求极致性能的话,建议不要配置该属性,因为不配置的时候会通过ping 命令进行连接检测,性能会更高。经过小规模测试得出,原生的ping命令性能是select的1倍左右。
( 6 ) minimumldle
minimumIdle 大致相当于 BoneCP 中的 minConnectionsPerPartition 参数。此属性控制 HikariCP 尝试在池中维护的最小空闲连接数。若空闲连接数低于此值且池中的总连接数小于maximumPoolSize,则HikariCP将尽最大努力快速有效地添加其他连接。然而,为了最大限度地提高性能和对峰值需求的响应能力,HikariCP的作者建议不要设置此值,而是允许HikariCP充当一个固定大小的连接池(如果minimumldle未设置则默认为
是maximumPoolSize,因此即使idleTimeout 设置为1分钟,一旦连接关闭,它也会在池中被替换)。如果设置这个值,那么HikariCP 就会是一个大小可变的池,通过 minimumIdle进行调解控制,即使使用情况上下浮动,HikariCP也会保持minimumldle连接可用。
minimumIdle 的默认值与 maximumPoolSize 相同。
minimumIdle 应始终小于或等于 maximumPoolSize。
如果minimumIdle设置为更高的值,maximumPoolSize 将被推高到相等的值。minimumIdle 逻辑上不能超过 maximumPoolSize,
因为maximumPoolSize指定了后端数据库的实际连接的最大数量。
如果有比 minimumldle 的数目更多的连接数,此时若一个连接退役了,则它不会被自动替换。但是如果数据库连接池被配置为固定大小,或者连接关闭后空闲连接小于minimumIdle 的数量,那么就会立即自动替换被关闭的连接。启用 HikariCP 的 metrics 采集,在可视化界面上可直观地显示连接的直方图,这有利于用户研究并确定正确、合理的minimumIdle 值及 idleTimeout 值。数据库连接池的调优最好基于经验数据,具体问题具体
分析。
( 7 ) maximumPoolSize
该属性控制数据库连接池连接数允许到达的最大值,包括空闲和正在使用的连接。基
本上,此值将决定数据库后端实际连接的最大数量。该属性的合理值最好由用户的执行环
境决定。当池达到此大小且没有空闲连接可用时,对 getConnection0的调用将阻塞到超时
前 connectionTimeout 毫秒。关于连接池大小 PoolSize的相关知识请关注本章后续内容。该
属性的默认值:10。
( 8)metricRegistry
该属性仅在编程配置或IoC容器中可用。该属性允许用户指定池使用的Codahale/Dropwizard实例MetricRegistry,来记录各种度量标准。如果用户需要使用Prometheus等监控,还需要做一些操作。
该属性的默认值:无。
( 9 ) healthCheckRegistry
该属性仅在编程配置或IoC容器中可用。该属性允许用户指定池使用的Codahale/Dropwizard实例HealthCheckRegistry,来报告当前系统的健康信息。该属性的默认值:无。
( 10 ) poolName
该属性表示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。该属性的默认值:自动生成。
这个配置在HikariCP 多个Datasource及监控的过程中非常有用,拥有poolName的HikariCP 监控远比 pool1、pool2、pool3 更容易帮助我们发现、分析、定位及解决问题。
2.非常用配置
非常用配置主要有15个,此外还有一些HikariCP官方文档没有记载、用于调试的极为不常用的“隐藏属性”。虽然在日常实际工作中我们并不一定会用到HikariCP的这些配置,但是在用到一些高级特性时,这些配置是可以发挥出巨大作用的。比如在故障注人演习的时候,allowPoolSuspension就可以支持一些故障转移自动化的方案;registerMbeans 属性在JMX监控中一定要打开并设置为true;再比如 leakDetectionThreshold 是检测 HikariCP 连接池泄露的利器。
( 1 ) initializationFailTimeout
如果池无法成功初始化连接,则此属性控制池是否“快速失败”。当该属性为正数时,该值为尝试获取初始连接的毫秒数。在此期间,应用程序线程将被阻塞。如果在超时发生之前无法获取连接,则将引发异常。initializationFailTimeout超时发生在connectionTimeout阶段之后。如果值为0,HikariCP将尝试获取并验证连接。如果获得连接但验证失败,则抛
出异常,而不会启动池。但是,如果无法获得连接,则池将启动,但稍后获取连接的尝试会失败。小于0的值将绕过任何初始连接尝试,并且池将尝试在后台获取连接时立即启动。
因此,以后获得连接的尝试可能会失败。该值的默认值:1。
( 2)isolateinternalQueries
此属性决定HikariCP是否在自己的事务中隔离内部池查询,例如连接存活测试。由于这些查询通常是只读查询,因此很少有必要将它们封装在自己的事务中。此属性仅在autoCommit 禁用时适用。默认值:false。
( 3 ) allowPoolSuspension
此属性控制池是否可以通过JMX挂起和恢复。这对某些故障转移自动化方案很有用。当池被挂起时,调用 getConnection()将不会超时,并将一直保持到池恢复为止。默认值:false。
( 4 ) readOnly
此属性控制默认情况下从池中获取的Connections是否处于只读模式。注意,某些数据库不支持只读模式的概念,而其他数据库在Connection设置为只读时提供查询优化功能。是否需要此属性将在很大程度上取决于用户的应用程序和数据库。默认值:false。
( 5 ) registerMbeans
此属性控制是否注册JMX以管理Bean(MBean)。默认值:false。
贴出一段通过jmx监控连接池的代码
@Component
public class HikariLogUtil {
private static Logger logger = LoggerFactory.getLogger(HikariLogUtil.class);
@Scheduled(fixedRate = 5000)
public void HikariMonitor() throws MalformedObjectNameException {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (设置的poolname)");
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class);
if (poolProxy == null) {
logger.info("Hikari not initialized,please wait...");
} else {
logger.info("HikariPoolState = "
+ "Active=[" + String.valueOf(poolProxy.getActiveConnections() + "] "
+ "Idle=[" + String.valueOf(poolProxy.getIdleConnections() + "] "
+ "Wait=[" + poolProxy.getThreadsAwaitingConnection() + "] "
+ "Total=[" + poolProxy.getTotalConnections() + "]"
+ "Time=[" + new Date() + "]")));
}
}
}
( 6 ) catalog
此属性为支持catalog的数据库设置默认catalog。如果未指定此属性,则使用JDBC驱动程序定义的默认catalog。
默认值:driver default。
( 7 ) connectionlnitSqI
此属性设置一个SQL语句,该语句将在每次创建新连接之后执行,然后再将该连接添加到池中。如果此SQL无效或抛出异常,则被视为连接失败,并将遵循标准重试逻辑。默
认值:无。
( 8 ) driverClassName
HikariCP将尝试仅基于jdbcUrl通过DriverManager解析驱动程序,但对于某些较旧的驱动程序必须指定driverClassName。除非用户收到明显的错误消息,表明未找到驱动程序,否则可忽略此属性。默认值:无。
( 9 ) transactionlsolation
此属性控制从池返回的连接的默认事务隔离级别。若未指定,则用JDBC驱动程序定义的默认事务隔离级别。仅当有针对所有查询的特定隔离需求时,才使用此属性。此属性的值是Connection类的常量名,如TRANSACTION_READ_COMMITTED、
TRANSACTION_REPEATABLE_READ 等。默认值:driver default。
( 10) validationTimeout
此属性控制连接测试活性的最长时间。该值必须小于connectionTimeout。最低可接受的验证超时为 250 毫秒。默认值:5000。
( 11 ) leakDetectionThreshold
此属性控制连接在记录一条指示可能连接泄露的消息之前流出池的时间。值为0表示禁用泄露检测。启用泄露检测的最低可接受值是2000毫秒(2秒)。默认值:0。
( 12) dataSource
此属性仅可通过编程配置或IoC容器获得。此属性允许用户直接设置DataSource要由池包装的实例,而不是让HikariCP通过反射构造该实例。这在一些依赖注入框架中很有用。指定此属性后,dataSourceClassName将忽略该属性和所有特定于DataSource的属性。
默认值:无。
( 13) schema
该属性为支持schema概念数据库设置默认schema,如果未指定此属性,则使用JDBC驱动程序定义的默认模式。默认值:driver default。
( 14 ) threadFactory
此属性仅可通过编程配置或IoC容器获得。通过配置该属性自定义设置java.util.concurrent.ThreadFactory的实例,可创建池使用的所有线程的实例。这个属性在某些受限制的环境中使用,在这些环境中,线程只能通过应用容器提供的 ThreadFactory 创建。默认值:无。
( 15 ) scheduledExecutor
仅可通过编程配置或IoC容器获得。通过该属性自定义设置java.util.concurrent.Scheduled-ExecutorService的实例,可实例化各种内部调度任务。如果向HikariCP提供ScheduledThread-
PoolExecutor实例,建议设置 setRemoveOnCancelPolicy(true)。默认值:无。
总结
SpringBoot项目如果我们通过启动器starter的方式使用JPA或者Mybatis作为数据库持久层框架访问数据库,都会默认自动启用HikariCP数据库连接池。实际项目上线时,可以根据项目的实际情况以及服务器情况设置合适的HikariCP配置项,让HikariCP数据库连接池提高对数据库操作的性能。
标题:SpringBoot数据库连接池Hikari配置
作者:michael
地址:https://blog.junxworks.cn/articles/2023/04/07/1680830522984.html