当前位置: 首页 > 工具软件 > flexy-pool > 使用案例 >

HikariCP 常见的异常及添加Flexy-Pool故障自动转移策略

吴山
2023-12-01

HikariCP 常见的异常是“Connection is not available,request timed out after”,这个异常通常是在数据库连接池已经达到了最大容量,且大量连接都在同时调用数据库连接池的getConnection 方法时产生的。不仅如此,它表明线程在调用 getConnection 等待了的一段时间(由确实connectionTimeout)内,希望连接返回到池,但是没有连接可用。它并不表示HikariCP提供了无效的连接,HikariCP 也几乎做不到这个功能。导致这个错误通常有两种可能:
1)连接泄露。在这种情况下,连接被借用但是从未返回。最终,池将耗尽连接,应用程序将永远阻塞。此时建议启用 leakDetectionThreshold,并将其设置为 connectionTimeout的2倍。如果在日志中看到连接泄露的告警,则应该提供指向泄露源的堆栈跟踪。
2)长时间运行的查询(执行时间超过connectionTimeout的查询)。

Flexy-Pool

Flexy-Pool将Metrics指标和灵活的Failover故障自动转移策略添加到指定的数据库连接池,允许数据库连接池按需调整大小,Flexy-Pool是一种reactive的连接池。其作者认为,连接池大小不是前期设计决定
的,在大型企业系统中,需要根据适应性和实际监控情况做出正确决策。Flexy-Pool为大多数数据库连接池,如Apache DBCP、Apache DBCP2、c3p0、BoneCP、HikariCP、Druid、Tomcat CP、Vibur DBCP 提供了一组有限的动态配置策略,对事务管理的 BitronixTransaction Manager、Atomikos TransactionsEssentials也提供了支持。
Vlad Mihalcea认为,不断测量和调整是控制生产环境数据库连接池大小的最好解决方法。捕获数据库连接池各项指标,以及在企业系统运行时调整给定连接池大小的工具就是Flexy-Pool。Flexy-Pool其实就是一个JDBC DataSource之前的或者其他代理之前的DataSource 级的代理。

HikariCP 是为具有相对恒定负载的系统而设计的,并且在该环境中池往往保持其最大大小,因此没有必要使代码复杂化以支持动态大小调整。配置的内容越多,用户就越难优化配置池。但是,因为最终有足够多的用户需要动态调整大小,并且若是缺少这种功能会给实际使用带来问题,所以HikariCP增加了对该功能的支持。
Flexy-Pool的作用就是解决如何自动调整不同负载下的最佳连接池设置的难题。连接池上限受到数据库最优并发查询容量的限制,这正是Hikari关于池大小起作用的地方。然而,在池的最小值和这个上限之间存在大量的配置空间,这里就是Flexy-Pool发挥价值的地方,即通过确保数据库连接池的正确大小,动态地为其服务的程序保证负载。
那么该如何使用Flexy-Pool 呢?对于 HikariCP 来说,首先需要引人依赖。

<dependency>
	<groupId>com.vladmihalcea.flexy-pool</groupId>
	<artifactId>flexy-hikaricp</artifactId>
	<version>${flexy-pool.version}</version>
</dependency>

然后进行数据库连接池的配置

<bean id="poolingDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
	<property name="dataSourceClassName" value="${jdbc.dataSourceClassName}" />
	<property name="dataSourceProperties">
		<props>
			<prop key="url">${jdbc.url}</prop>
			<prop key="user">${jdbc.username}</prop>
			<prop key="password">${jdbc.password}</prop>
		</props>
	</property>
	<property name="minimumPoolSize" value="1"/>
	<property name="maximumPoolSize" value="3"/>
	<property name="connectionTimeout" value="1000"/>
</bean>

如果是Spring注解的形式,就按照如下方式配置Flexy-Pool:

@org.springframework.context.annotation.Configuration
public class FlexyPoolConfiguration {

    @Autowired
    private HikariDataSource poolingDataSource;

    @Value("${flexy.pool.uniqueId}")
    private String uniqueId;

    @Bean
    public Configuration<HikariDataSource> configuration() {
        return new Configuration.Builder<HikariDataSource>(
                uniqueId,
                poolingDataSource,
                HikariCPPoolAdapter.FACTORY
        ).build();
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    public FlexyPoolDataSource dataSource() {
        Configuration<HikariDataSource> configuration = configuration();
        return new FlexyPoolDataSource<HikariDataSource>(configuration,
                new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory(5),
                new RetryConnectionAcquiringStrategy.Factory(2)
        );
    }
}

果是Spring XML的形式,可以按照如下方式配置:

<bean id="configurationBuilder" class="com.vladmihalcea.flexypool.config.Configuration$Builder">
	<constructor-arg value="uniqueId"/>
	<constructor-arg ref="poolingDataSource"/>
	<constructor-arg value="#{ T(com.vladmihalcea.flexypool.adaptor.HikariCPPoolAdapter).FACTORY }"/>
</bean>

<bean id="configuration" factory-bean="configurationBuilder" factory-method="build"/>

<bean id="dataSource" class="com.vladmihalcea.flexypool.FlexyPoolDataSource" init-method="start" destroy-method="stop">
	<constructor-arg ref="configuration"/>
	<constructor-arg>
		<array>
			<bean class="com.vladmihalcea.flexypool.strategy.IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory">
				<constructor-arg value="5"/>
			</bean>
			<bean class="com.vladmihalcea.flexypool.strategy.RetryConnectionAcquiringStrategy.Factory">
				<constructor-arg value="2"/>
			</bean>
		</array>
	</constructor-arg>
</bean>
 类似资料: