-
Notifications
You must be signed in to change notification settings - Fork 120
Installation Guide
This is the latest FlexyPool release version:
<flexy-pool.version>3.0.2</flexy-pool.version>
Make sure you add this to your pom.xml.
If you want to use the Micrometer framework for metrics instead of Dropwizard Metrics, then you need to add the flexy-micrometer-metrics
dependency and exclude the flexy-dropwizard-metrics
dependency from the connection pool-specific FlexyPool dependency (e.g. flexy-hikaricp):
<dependency>
<groupId>com.vladmihalcea.flexy-pool</groupId>
<artifactId>flexy-micrometer-metrics</artifactId>
<version>${flexy-pool.version}</version>
</dependency>
<dependency>
<groupId>com.vladmihalcea.flexy-pool</groupId>
<artifactId>flexy-hikaricp</artifactId>
<version>${flexy-pool.version}</version>
<exclusions>
<exclusion>
<groupId>com.vladmihalcea.flexy-pool</groupId>
<artifactId>flexy-dropwizard-metrics</artifactId>
</exclusion>
</exclusions>
</dependency>
For Spring Boot, check out this flexy-pool-spring-boot-starter written by Arthur Gavlyukovskiy.
Depending on your current project connection pool choice you need to follow one of these guides first:
-
JDBC Connection Pools
-
JTA Transaction Managers
Each FlexyPool instance requires a data source specific Configuration, which is supplied prior to constructing a FlexyPoolDataSource instance. You’ll have to rename your target Data Source (e.g from dataSource to poolingDataSource), as the FlexyPool Data Source will impersonate the actual Data Source.
A full Configuration would look like this:
@Configuration
public class FlexyPoolBeanConfiguration {
public static class ConnectionAcquisitionTimeThresholdExceededEventListener
extends EventListener<ConnectionAcquisitionTimeThresholdExceededEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(
ConnectionAcquisitionTimeThresholdExceededEventListener.class);
public ConnectionAcquisitionTimeThresholdExceededEventListener() {
super(ConnectionAcquisitionTimeThresholdExceededEvent.class);
}
@Override
public void on(ConnectionAcquisitionTimeThresholdExceededEvent event) {
LOGGER.info("Caught event {}", event);
}
}
public static class ConnectionLeaseTimeThresholdExceededEventListener
extends EventListener<ConnectionLeaseTimeThresholdExceededEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(
ConnectionLeaseTimeThresholdExceededEventListener.class);
public ConnectionLeaseTimeThresholdExceededEventListener() {
super(ConnectionLeaseTimeThresholdExceededEvent.class);
}
@Override
public void on(ConnectionLeaseTimeThresholdExceededEvent event) {
LOGGER.info("Caught event {}", event);
}
}
public static class ConnectionAcquisitionTimeoutEventListener
extends EventListener<ConnectionAcquisitionTimeoutEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(
ConnectionAcquisitionTimeoutEventListener.class);
public ConnectionAcquisitionTimeoutEventListener() {
super(ConnectionAcquisitionTimeoutEvent.class);
}
@Override
public void on(ConnectionAcquisitionTimeoutEvent event) {
LOGGER.info("Caught event {}", event);
}
}
@Autowired
private HikariDataSource poolingDataSource;
@Value("${flexy.pool.uniqueId}")
private String uniqueId;
@Bean
public FlexyPoolConfiguration<HikariDataSource> configuration() {
return new FlexyPoolConfiguration.Builder<HikariDataSource>(
uniqueId,
poolingDataSource,
HikariCPPoolAdapter.FACTORY
)
.setMetricsFactory(MetricsFactoryResolver.INSTANCE.resolve())
.setConnectionProxyFactory(ConnectionDecoratorFactoryResolver.INSTANCE.resolve())
.setMetricLogReporterMillis(TimeUnit.SECONDS.toMillis(5))
.setMetricNamingUniqueName(UniqueNamingStrategy.INSTANCE)
.setJmxEnabled(true)
.setJmxAutoStart(true)
.setConnectionAcquisitionTimeThresholdMillis(50L)
.setConnectionLeaseTimeThresholdMillis(250L)
.setEventListenerResolver(() -> Arrays.<EventListener<? extends Event>>asList(
new ConnectionAcquisitionTimeoutEventListener(),
new ConnectionAcquisitionTimeThresholdExceededEventListener(),
new ConnectionLeaseTimeThresholdExceededEventListener()
) )
.build();
}
@Bean(initMethod = "start", destroyMethod = "stop")
public FlexyPoolDataSource dataSource() {
FlexyPoolConfiguration<HikariDataSource> configuration = configuration();
return new FlexyPoolDataSource<HikariDataSource>(configuration,
new IncrementPoolOnTimeoutConnectionAcquisitionStrategy.Factory(5),
new RetryConnectionAcquisitionStrategy.Factory(2)
);
}
}
Parameter name | Parameter type | Optional | Default value | Description |
---|---|---|---|---|
uniqueName |
Supplied through FlexyPoolConfiguration.Builder constructor |
false |
N/A |
Each FlexyPool instance requires a unique name so that JMX domains won’t clash |
targetDataSource |
Supplied through FlexyPoolConfiguration.Builder constructor |
false |
N/A |
The target DataSource we are monitoring |
poolAdapterFactory |
Supplied through FlexyPoolConfiguration.Builder constructor |
false |
N/A |
The specific pool adaptor factory associated with the target DataSource |
metricsFactory |
Supplied through FlexyPoolConfiguration.Builder setMetricsFactory |
true |
DropwizardMetrics.FACTORY |
The metrics factory allows customizing the metrics implementation. A Dropwizard Metrics implementation is being supplied |
connectionProxyFactory |
Supplied through FlexyPoolConfiguration.Builder setConnectionProxyFactory |
true |
ConnectionDecoratorFactory.INSTANCE |
The connection proxy provider. You can choose between decorating Connections and a JDK Dynamic Proxies implementation |
jmxEnabled |
Supplied through FlexyPoolConfiguration.Builder setJmxEnabled |
true |
true |
Specifies if the JMX service is enabled |
metricLogReporterMillis |
Supplied through FlexyPoolConfiguration.Builder setMetricLogReporterMillis |
true |
TimeUnit.MINUTES.toMillis(5) |
Specifies the metrics log reported interval |
metricNamingUniqueName |
Supplied through FlexyPoolConfiguration.Builder setMetricNamingUniqueName |
true |
com.vladmihalcea.flexypool.strategy.DefaultNamingStrategy |
Specifies a class name that implements the |
eventListenerResolver |
Supplied through FlexyPoolConfiguration.Builder setEventListenerResolver |
true |
N/A |
Specifies a class name responsible for supplying the EventListener implementations |
connectionAcquisitionTimeThresholdMillis |
Supplied through FlexyPoolConfiguration.Builder setConnectionAcquisitionTimeThresholdMillis |
true |
Long.MAX_VALUE |
Specifies a time threshold for the connection acquisition request. When the time limit is exceeded a log entry will be generated and a ConnectionAcquisitionTimeThresholdExceededEvent will be published. |
connectionLeaseTimeThresholdMillis |
Supplied through FlexyPoolConfiguration.Builder setConnectionLeaseTimeThresholdMillis |
true |
Long.MAX_VALUE |
Specifies a time threshold for the connection lease. When the time limit is exceeded a log entry will be generated and a ConnectionLeaseTimeThresholdExceededEvent will be published. |
@Bean(initMethod = "start", destroyMethod = "stop")
public FlexyPoolDataSource dataSource() {
Configuration<HikariDataSource> configuration = configuration();
return new FlexyPoolDataSource<HikariDataSource>(configuration,
new IncrementPoolOnTimeoutConnectionAcquisitionStrategy.Factory(5),
new RetryConnectionAcquisitionStrategy.Factory(2)
);
}
Parameter name | Optional | Description |
---|---|---|
configuration |
false |
Each FlexyPool instance requires it’s own configuration |
strategies |
true |
The strategies will be applied when fetching a connection from the target connection pool. You can set up any number of strategies and they will be applied in the same order they were supplied |
A Strategy is a connection acquiring safety mechanisms, a resort that’s called when a connection is not successfully fetched from the target Connection Pool. You can define your own Strategies since this is a trivial job to do.
FlexyPool comes with the following default strategies
This strategy will increment the target connection pool maximum size on connection acquisition timeout.
Parameter name | Optional | Description |
---|---|---|
maxOvergrowPoolSize |
false |
This is the maximum limit a target connection pool can stretch to |
timeoutMillis |
true |
If the connection acquiring time takes more than this value a pool size increment is attempted. If this value is not supplied, the target pool timeout will be used instead, so that when the target pool throws a timeout exception the pool size increment is attempted. |
The connection pool has a minimum size and on demand it can grow up to its maximum size. The overgrow is a buffer of extra connections allowing the connection pool to grow beyond its initial maximum size. Whenever a connection acquisition timeout is detected, the current request won’t fail if the pool hasn’t grown to it’s maxOvergrowPoolSize.
It’s safe to set the target connection pool acquiring timeout interval to a value that’s appropriate for your application wait expectations. You might also set the connection expiring interval to free up unused connections, releasing them when they are no longer required.
A DBCP example setting the initial maximum size and the acquiring timeout interval.
<bean id="poolingDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="3"/>
<property name="maxWait" value="100"/>
</bean>
This strategy is useful for those connection pools lacking a connection acquiring retry mechanism
Parameter name | Optional | Description |
---|---|---|
retryAttempts |
false |
This is the maximum number of retries attempts before giving up |
You can register your own event handlers for the following events:
-
ConnectionAcquisitionTimeoutEvent (generated when a connection acquisition timeout exception is thrown)
-
ConnectionAcquisitionTimeThresholdExceededEvent (generated when the connection acquisition threshold given by the connectionAcquisitionTimeThresholdMillis configuration property is exceeded)
-
ConnectionLeaseTimeThresholdExceededEvent (generated when the connection lease threshold given by the connectionLeaseTimeThresholdMillis configuration property is exceeded)
To supply the custom event listeners you should use the eventListenerResolver configuration property.
You should be aware that these events are published synchronously so you should avoid executing some time-consuming event handling logic because that would add an extra overhead to the current transaction and connection holding. If your event handling logic is time-consuming, you should consider submitting the event to an ExecutorService and execute it in one of its own worker threads.
An enterprise system must have use an integrated monitoring report tool, such as Ganglia or Graphite and it’s easy to instruct FlexyPool to use a different reporting mechanism than the default ones.
You may wish to customize different Reservoirs for specific Metrics or to use a CSV reporter and this is how you can do it:
FlexyPoolConfiguration<DataSource> configuration = new FlexyPoolConfiguration.Builder<>(
"unique",
dataSource,
poolAdapterFactory
)
.setConnectionProxyFactory(connectionProxyFactory)
.setJmxAutoStart(true)
.setJmxEnabled(true)
.setMetricLogReporterMillis(120)
.setMetricsFactory(
configurationProperties -> new DropwizardMetrics(
configurationProperties,
metricRegistry,
(metricClass, metricName) -> new ExponentiallyDecayingReservoir()
)
)
.build();