HikariCP 除了dadaSourceClassName/jdbcUrl、username、password 这三个必须配置之外,HikariCP 还有一些非必须配置,非必需配置包含的常用配置和非常用配置都是可选的。
HikariCP 强烈反对向池中添加大量参数配置,这样会使代码复杂化,所以迫使用户必须考虑配置是否必须,这导致调整数据库连接池这项工作变得复杂。Apache DBCP 有超过40 个连接池属性,但是估计实际生产中 90% 使用 DBCP 的应用部署并没有正确调整性能和可靠性。
常用配置有 10个,我们一起看看它们都有哪些,都是做什么的,默认值是什么。
此属性控制从连接池返回的连接的默认自动提交事务行为。它是一个布尔值,默认值:true。
此属性控制客户端(即用户的程序)等待池中连接的最长毫秒数。如果在没有连接可用的情况下超过此时间,则将抛出 SQLException 异常。最低可接受的连接超时为 250 毫秒。默认值:30000(30秒)。这是一个很重要的问题排查指标。
此属性控制连接允许被闲置在池中的最大时间。此设置仅适用于 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。
该属性仅在编程配置或IoC容器中可用。该属性允许用户指定池使用的Codahale/Dropwizard实例MetricRegistry,来记录各种度量标准。如果用户需要使用Prometheus等监控,还需要做一些操作。
该属性的默认值:无。
该属性仅在编程配置或IoC容器中可用。该属性允许用户指定池使用的Codahale/Dropwizard实例HealthCheckRegistry,来报告当前系统的健康信息。该属性的默认值:无。
该属性表示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。该属性的默认值:自动生成。
这个配置在HikariCP 多个Datasource及监控的过程中非常有用,拥有poolName的HikariCP 监控远比 pool1、pool2、pool3 更容易帮助我们发现、分析、定位及解决问题。
如果驱动程序支持JDBC4,则建议不要设置此属性。这适用于不支持JDBC4的Connection.isValid()的“遗留”驱动程序API。这是一个检测查询,在数据库连接池给出连接之前进行查询,以验证与数据库的连接是否仍然存在且有效。同样,尝试运行数据库连接池并不配置该属性,如果你的驱动程序不支持JDBC4,那么HikariCP将报错。该属性默认值:无。
注意,如果你追求极致性能的话,建议不要配置该属性,因为不配置的时候会通过ping 命令进行连接检测,性能会更高。经过小规模测试得出,原生的ping命令性能是select的1倍左右。
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 值。数据库连接池的调优最好基于经验数据,具体问题具体分析。
该属性控制数据库连接池连接数允许到达的最大值,包括空闲和正在使用的连接。基本上,此值将决定数据库后端实际连接的最大数量。该属性的合理值最好由用户的执行环境决定。当池达到此大小且没有空闲连接可用时,对 getConnection0的调用将阻塞到超时前 connectionTimeout 毫秒。关于连接池大小 PoolSize的相关知识请关注本章后续内容。该属性的默认值:10。
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.
这个问题分两种情况来看,是立即发生还是一段时间以后发生?如果是一段时间以后发生,一般是因为数据库的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分钟。
非常用配置主要有15个,此外还有一些HikariCP官方文档没有记载、用于调试的极为不常用的“隐藏属性”。虽然在日常实际工作中我们并不一定会用到HikariCP的这些配置,但是在用到一些高级特性时,这些配置是可以发挥出巨大作用的。比如在故障注人演习的时候,allowPoolSuspension就可以支持一些故障转移自动化的方案;registerMbeans 属性在JMX监控中一定要打开并设置为true;再比如 leakDetectionThreshold 是检测 HikariCP 连接池泄露的利器。
如果池无法成功初始化连接,则此属性控制池是否“快速失败”。当该属性为正数时,该值为尝试获取初始连接的毫秒数。在此期间,应用程序线程将被阻塞。如果在超时发生之前无法获取连接,则将引发异常。initializationFailTimeout超时发生在connectionTimeout阶段之后。如果值为0,HikariCP将尝试获取并验证连接。如果获得连接但验证失败,则抛出异常,而不会启动池。但是,如果无法获得连接,则池将启动,但稍后获取连接的尝试会失败。小于0的值将绕过任何初始连接尝试,并且池将尝试在后台获取连接时立即启动。
因此,以后获得连接的尝试可能会失败。该值的默认值:1。
此属性控制是否注册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() + "]"))); } } }
此属性为支持catalog的数据库设置默认catalog。如果未指定此属性,则使用JDBC驱动程序定义的默认catalog。
默认值:driver default。
此属性设置一个SQL语句,该语句将在每次创建新连接之后执行,然后再将该连接添加到池中。如果此SQL无效或抛出异常,则被视为连接失败,并将遵循标准重试逻辑。默
认值:无。
此属性决定HikariCP是否在自己的事务中隔离内部池查询,例如连接存活测试。由于这些查询通常是只读查询,因此很少有必要将它们封装在自己的事务中。此属性仅在autoCommit 禁用时适用。默认值:false。
此属性控制池是否可以通过JMX挂起和恢复。这对某些故障转移自动化方案很有用。当池被挂起时,调用 getConnection()将不会超时,并将一直保持到池恢复为止。默认值:false。
此属性控制默认情况下从池中获取的Connections是否处于只读模式。注意,某些数据库不支持只读模式的概念,而其他数据库在Connection设置为只读时提供查询优化功能。是否需要此属性将在很大程度上取决于用户的应用程序和数据库。默认值:false。
HikariCP将尝试仅基于jdbcUrl通过DriverManager解析驱动程序,但对于某些较旧的驱动程序必须指定driverClassName。除非用户收到明显的错误消息,表明未找到驱动程序,否则可忽略此属性。默认值:无。
该属性为支持schema概念数据库设置默认schema,如果未指定此属性,则使用JDBC驱动程序定义的默认模式。默认值:driver default。
此属性仅可通过编程配置或IoC容器获得。通过配置该属性自定义设置java.util.concurrent.ThreadFactory的实例,可创建池使用的所有线程的实例。这个属性在某些受限制的环境中使用,在这些环境中,线程只能通过应用容器提供的 ThreadFactory 创建。默认值:无。
仅可通过编程配置或IoC容器获得。通过该属性自定义设置java.util.concurrent.Scheduled-ExecutorService的实例,可实例化各种内部调度任务。如果向HikariCP提供ScheduledThread-PoolExecutor实例,建议设置 setRemoveOnCancelPolicy(true)。默认值:无。
此属性控制从池返回的连接的默认事务隔离级别。若未指定,则用JDBC驱动程序定义的默认事务隔离级别。仅当有针对所有查询的特定隔离需求时,才使用此属性。此属性的值是Connection类的常量名,如TRANSACTION_READ_COMMITTED、TRANSACTION_REPEATABLE_READ 等。默认值:driver default。
此属性控制连接测试活性的最长时间。该值必须小于connectionTimeout。最低可接受的验证超时为 250 毫秒。默认值:5000。
此属性控制连接在记录一条指示可能连接泄露的消息之前流出池的时间。值为0表示禁用泄露检测。启用泄露检测的最低可接受值是2000毫秒(2秒)。默认值:0。
此属性仅可通过编程配置或IoC容器获得。此属性允许用户直接设置DataSource要由池包装的实例,而不是让HikariCP通过反射构造该实例。这在一些依赖注入框架中很有用。指定此属性后,dataSourceClassName将忽略该属性和所有特定于DataSource的属性。默认值:无。