hikaripool信息_聊聊hikari连接池的fixed pool design

本文深入探讨了Hikari连接池的固定池设计,解释了为何建议将minimumIdle和maximumPoolSize设置为相同值以避免流量激增时的性能损失。Hikari通过HouseKeeperTask维护连接,确保在固定连接数下保持性能。对比了Tomcat JDBC Pool,HikariCP提供了maxLifetime参数以保证连接池的活性。
摘要由CSDN通过智能技术生成

本文主要研究一下hikari连接池的fixed pool design

fixed pool design

hikari的作者比较倾向于fixed pool design的理念,即建议minimumIdle与maximumPoolSize设置成一样,当做固定连接大小的连接池。作者认为minimumIdle小于maximumPoolSize的话,在流量激增的时候需要额外的连接,此时在请求方法里头再去处理新建连接会造成性能损失,即会导致数据库一方面降低连接建立的速度,另一方面也会影响既有的连接事务的完成,间接影响了这些既有连接归还到连接池的速度。

作者认为minimumIdle与maximumPoolSize设置成一样,多余的空闲连接不会对整体的性能有什么严重影响,如果说设置minimumIdle小于maximumPoolSize是为了在必要的时候可以释放连接以释放内存给其他功能用,但是在高峰时期,连接池可能也会到达maximumPoolSize,因而这个目的似乎没起到效果。

HikariPool.houseKeeperTask

HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java

private final long HOUSEKEEPING_PERIOD_MS = Long.getLong("com.zaxxer.hikari.housekeeping.periodMs", SECONDS.toMillis(30));

/**

* Construct a HikariPool with the specified configuration.

*

* @param config a HikariConfig instance

*/

public HikariPool(final HikariConfig config)

{

super(config);

this.connectionBag = new ConcurrentBag<>(this);

this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK;

this.houseKeepingExecutorService = initializeHouseKeepingExecutorService();

checkFailFast();

if (config.getMetricsTrackerFactory() != null) {

setMetricsTrackerFactory(config.getMetricsTrackerFactory());

}

else {

setMetricRegistry(config.getMetricRegistry());

}

setHealthCheckRegistry(config.getHealthCheckRegistry());

registerMBeans(this);

ThreadFactory threadFactory = config.getThreadFactory();

LinkedBlockingQueue addConnectionQueue = new LinkedBlockingQueue<>(config.getMaximumPoolSize());

this.addConnectionQueue = unmodifiableCollection(addConnectionQueue);

this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardPolicy());

this.closeConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());

this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService);

this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, HOUSEKEEPING_PERIOD_MS, MILLISECONDS);

}

在初始化HikariPool的时候会初始化houseKeeperTask

HikariPool.HouseKeeper

HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java

/**

* The house keeping task to retire and maintain minimum idle connections.

*/

private final class HouseKeeper implements Runnable

{

private volatile long previous = plusMillis(currentTime(), -HOUSEKEEPING_PERIOD_MS);

@Override

public void run()

{

try {

// refresh timeouts in case they changed via MBean

connectionTimeout = config.getConnectionTimeout();

validationTimeout = config.getValidationTimeout();

leakTaskFactory.updateLeakDetectionThreshold(config.getLeakDetectionThreshold());

final long idleTimeout = config.getIdleTimeout();

final long now = currentTime();

// Detect retrograde time, allowing +128ms as per NTP spec.

if (plusMillis(now, 128) < plusMillis(previous, HOUSEKEEPING_PERIOD_MS)) {

LOGGER.warn("{} - Retrograde clock change detected (housekeeper delta={}), soft-evicting connections from pool.",

poolName, elapsedDisplayString(previous, now));

previous = now;

softEvictConnections();

return;

}

else if (now > plusMillis(previous, (3 * HOUSEKEEPING_PERIOD_MS) / 2)) {

// No point evicting for forward clock motion, this merely accelerates connection retirement anyway

LOGGER.warn("{} - Thread starvation or clock leap detected (housekeeper delta={}).", poolName, elapsedDisplayString(previous, now));

}

previous = now;

String afterPrefix = "Pool ";

if (idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()) {

logPoolState("Before cleanup ");

afterPrefix = "After cleanup ";

final List notInUse = connectionBag.values(STATE_NOT_IN_USE);

int toRemove = notInUse.size() - config.getMinimumIdle();

for (PoolEntry entry : notInUse) {

if (toRemove > 0 && elapsedMillis(entry.lastAccessed, now) > idleTimeout && connectionBag.reserve(entry)) {

closeConnection(entry, "(connection has passed idleTimeout)");

toRemove--;

}

}

}

logPoolState(afterPrefix);

fillPool(); // Try to maintain minimum connections

}

catch (Exception e) {

LOGGER.error("Unexpected exception in housekeeping task", e);

}

}

}

假设minimumIdle与maximumPoolSize设置成一样,那么这个task在第一次执行的时候,直接执行fillPool

fillPool

/**

* Fill pool up from current idle connections (as they are perceived at the point of execution) to minimumIdle connections.

*/

private synchronized void fillPool()

{

final int connectionsToAdd = Math.min(config.getMaximumPoolSize() - getTotalConnections(), config.getMinimumIdle() - getIdleConnections())

- addConnectionQueue.size();

for (int i = 0; i < connectionsToAdd; i++) {

addConnectionExecutor.submit((i < connectionsToAdd - 1) ? POOL_ENTRY_CREATOR : POST_FILL_POOL_ENTRY_CREATOR);

}

}

这个fillPool,在初始化时刻,minimumIdle与maximumPoolSize值一样,totalConnections与idleConnections都为0,那么connectionsToAdd的值就是maximumPoolSize

也就是说这个task会添加maximumPoolSize大小连接

小结

tomcat jdbc pool

有个initial-size参数来指定最开始的时候初始化多少个连接,有min-idle及max-idle来控制空闲连接的最小值及最大值,有max-active来控制连接池总大小。min-evictable-idle-time-millis用来指定空闲连接的时长,time-between-eviction-runs-millis用来指定清理空闲连接的任务的调度时间间隔。

hikari connection pool

有minIdle来指定空闲连接的最小数量,maxPoolSize指定连接池连接最大值,默认初始化的时候,是初始化minIdle大小的连接,如果minIdle与maxPoolSize值相等那就是初始化时把连接池填满。idleTimeout用来指定空闲连接的时长,maxLifetime用来指定所有连接的时长。com.zaxxer.hikari.housekeeping.periodMs用来指定连接池空闲连接处理及连接池数补充的HouseKeeper任务的调度时间间隔。

也就是说hikari比tomcat jdbc pool多了个maxLifetime,也就是所有的连接在maxLifetime之后都得重连一次,保证连接池的活性。

doc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值