php 连接池 idletime,聊聊hikari连接池的idleTimeout及minimumIdle属性
序
本文主要研究一个hikari连接池的idleTimeout及minimumIdle属性
idleTimeout
默认是600000毫秒,即10分钟。如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,则会被重置为0;如果idleTimeout!=0且小于10秒,则会被重置为10秒。如果idleTimeout=0则表示空闲的连接在连接池中永远不被移除。
只有当minimumIdle小于maximumPoolSize时,这个参数才生效,当空闲连接数超过minimumIdle,而且空闲时间超过idleTimeout,则会被移除。
minimumIdle
控制连接池空闲连接的最小数量,当连接池空闲连接少于minimumIdle,而且总共连接数不大于maximumPoolSize时,HikariCP会尽力补充新的连接。为了性能考虑,不建议设置此值,而是让HikariCP把连接池当做固定大小的处理,默认minimumIdle与maximumPoolSize一样。
当minIdle<0或者minIdle>maxPoolSize,则被重置为maxPoolSize,该值默认为10。
HikariPool.HouseKeeper
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));
this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, HOUSEKEEPING_PERIOD_MS, MILLISECONDS);
/**
* 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);
}
}
}
这个HouseKeeper是一个定时任务,在HikariPool构造器里头初始化,默认的是初始化后100毫秒执行,之后每执行完一次之后隔HOUSEKEEPING_PERIOD_MS(30秒)时间执行。
这个定时任务的作用就是根据idleTimeout的值,移除掉空闲超时的连接。
首先检测时钟是否倒退,如果倒退了则立即对过期的连接进行标记evict;之后当idleTimeout>0且配置的minimumIdle
取出状态是STATE_NOT_IN_USE的连接数,如果大于minimumIdle,则遍历STATE_NOT_IN_USE的连接的连接,将空闲超时达到idleTimeout的连接从connectionBag移除掉,若移除成功则关闭该连接,然后toRemove--。
在空闲连接移除之后,再调用fillPool,尝试补充空间连接数到minimumIdle值
HikariPool.fillPool
HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java
private final PoolEntryCreator POOL_ENTRY_CREATOR = new PoolEntryCreator(null /*logging prefix*/);
private final PoolEntryCreator POST_FILL_POOL_ENTRY_CREATOR = new PoolEntryCreator("After adding ");
LinkedBlockingQueue addConnectionQueue = new LinkedBlockingQueue<>(config.getMaximumPoolSize());
this.addConnectionQueue = unmodifiableCollection(addConnectionQueue);
this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardPolicy());
/**
* 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);
}
}
PoolEntryCreator
/**
* Creating and adding poolEntries (connections) to the pool.
*/
private final class PoolEntryCreator implements Callable
{
private final String loggingPrefix;
PoolEntryCreator(String loggingPrefix)
{
this.loggingPrefix = loggingPrefix;
}
@Override
public Boolean call() throws Exception
{
long sleepBackoff = 250L;
while (poolState == POOL_NORMAL && shouldCreateAnotherConnection()) {
final PoolEntry poolEntry = createPoolEntry();
if (poolEntry != null) {
connectionBag.add(poolEntry);
LOGGER.debug("{} - Added connection {}", poolName, poolEntry.connection);
if (loggingPrefix != null) {
logPoolState(loggingPrefix);
}
return Boolean.TRUE;
}
// failed to get connection from db, sleep and retry
quietlySleep(sleepBackoff);
sleepBackoff = Math.min(SECONDS.toMillis(10), Math.min(connectionTimeout, (long) (sleepBackoff * 1.5)));
}
// Pool is suspended or shutdown or at max size
return Boolean.FALSE;
}
/**
* We only create connections if we need another idle connection or have threads still waiting
* for a new connection. Otherwise we bail out of the request to create.
*
* @return true if we should create a connection, false if the need has disappeared
*/
private boolean shouldCreateAnotherConnection() {
return getTotalConnections() < config.getMaximumPoolSize() &&
(connectionBag.getWaitingThreadCount() > 0 || getIdleConnections() < config.getMinimumIdle());
}
}
shouldCreateAnotherConnection方法决定了是否需要添加新的连接
createPoolEntry
/**
* Creating new poolEntry. If maxLifetime is configured, create a future End-of-life task with 2.5% variance from
* the maxLifetime time to ensure there is no massive die-off of Connections in the pool.
*/
private PoolEntry createPoolEntry()
{
try {
final PoolEntry poolEntry = newPoolEntry();
final long maxLifetime = config.getMaxLifetime();
if (maxLifetime > 0) {
// variance up to 2.5% of the maxlifetime
final long variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0;
final long lifetime = maxLifetime - variance;
poolEntry.setFutureEol(houseKeepingExecutorService.schedule(
() -> {
if (softEvictConnection(poolEntry, "(connection has passed maxLifetime)", false /* not owner */)) {
addBagItem(connectionBag.getWaitingThreadCount());
}
},
lifetime, MILLISECONDS));
}
return poolEntry;
}
catch (Exception e) {
if (poolState == POOL_NORMAL) { // we check POOL_NORMAL to avoid a flood of messages if shutdown() is running concurrently
LOGGER.debug("{} - Cannot acquire connection from data source", poolName, (e instanceof ConnectionSetupException ? e.getCause() : e));
}
return null;
}
}
createPoolEntry方法创建一个poolEntry,同时给它的lifetime过期设定了一个延时任务。
小结
HouseKeeper是一个定时任务,在HikariPool构造器里头初始化,默认的是初始化后100毫秒执行,之后每执行完一次之后隔HOUSEKEEPING_PERIOD_MS(30秒)时间执行。
如果发现时钟倒退,则立即标记evict连接,然后退出;否则都会执行fillPool,来试图维持空闲连接到minimumIdle的数值
当idleTimeout>0且配置的minimumIdle
当minIdle<0或者minIdle>maxPoolSize,则minIdle被重置为maxPoolSize,该值默认为10,官方建议设置为一致,当做固定大小的连接池处理提高性能
idleTimeout有点类似tomcat jdbc pool里头的min-evictable-idle-time-millis参数。不同的是tomcat jdbc pool的连接泄露检测以及空闲连接清除的工作都放在一个名为PoolCleaner的timerTask中处理,该任务的执行间隔为timeBetweenEvictionRunsMillis,默认为5秒;而hikari的连接泄露是每次getConnection的时候单独触发一个延时任务来处理,而空闲连接的清除则是使用HouseKeeper定时任务来处理,其运行间隔由com.zaxxer.hikari.housekeeping.periodMs环境变量控制,默认为30秒。
doc
php 连接池 idletime,聊聊hikari连接池的idleTimeout及minimumIdle属性相关推荐
- 聊聊hikari连接池的isAllowPoolSuspension
序 本文主要研究一下hikari连接池的isAllowPoolSuspension属性 实例代码 @Testpublic void testPoolSuspend() throws SQLExcept ...
- 聊聊hikari连接池的maxLifetime属性及evict操作
序 本文主要研究一下hikari连接池的maxLifetime属性及evict操作 maxLifetime属性及evict操作 maxLifetime 用来设置一个connection在连接池中的存活 ...
- 聊聊hikari连接池的maxLifetime属性及evict操作 1
序 本文主要研究一下hikari连接池的maxLifetime属性及evict操作 maxLifetime属性及evict操作 maxLifetime 用来设置一个connection在连接池中的存活 ...
- hikaripool连接保持_springboot2的hikari数据库连接池默认配置
序 Spring-Boot-2.0.0-M1版本将默认的数据库连接池从tomcat jdbc pool改为了hikari,这里主要研究下hikari的默认配置 spring-configuration ...
- 【追光者系列】Hikari连接池大小多大合适?(第一弹)
摘要: 原创出处微信公众号 「工匠小猪猪的技术世界」欢迎转载,保留摘要,谢谢! 1.这是一个系列,有兴趣的朋友可以持续关注 2.如果你有HikariCP使用上的问题,可以给我留言,我们一起沟通讨论 3 ...
- Hikari连接池——java.lang.Exception: Apparent connection leak detected
Hikari连接池--java.lang.Exception: Apparent connection leak detected 问题分析 总结 问题分析 首先,先看报错: java.lang.Ex ...
- 微服务架构师封神之路09-Springboot多数据源,Hikari连接池和事务配置
微服务架构师封神之路09-Springboot多数据源,Hikari连接池,和事务的配置 application.yml 初始化DataSource DataSourceConfig的两种写法 写法一 ...
- spring-boot配置MySQL数据库连接、Hikari连接池、和Mybatis的简单方法
此方法为极简配置,支持MySQL数据库多库连接.支持Hikari连接池.支持MyBatis(包括Dao类和xml文件位置的配置). 如果需要更灵活的自定义配置(比如支持分页插件),请参考:http:/ ...
- Connection is not available, request timed out after xxxms. 超时异常 Hikari连接池配置说明
## 数据库配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.driverClassName ...
最新文章
- datetime处理日期和时间
- centos下svn与mysql_centos下SVN搭建
- Spring事务管理--嵌套事务详解
- JVM Attach机制实现
- BZOJ_1629_[Usaco2007_Demo]_Cow_Acrobats_(贪心)
- C 标准库—— assert.h
- 多线程之-并发任务间交换数据
- 一种单片机支持WiFi的应用——SimpleWiFi在单片机中的应用
- CISP 考试教材《第 9 章 知识域:计算环境安全》知识整理
- python浏览器复制粘贴到word里(带格式的)
- RAC修改IP(public/virtual/scan)
- 冒泡详解(分析每一步)
- C# chart实时曲线
- matlab读取mp4视频,【Matlab系列】之视频文件读取和显示的方法
- IOS个人开发者账号和wp公司开发者帐号申请注意点
- 日本企业遭遇严重用工短缺
- 实现网站的高并发访问
- python列表get方法_Python json.get方法代码示例
- nyist oj nyoj 865
- 使用电源管理模块有效控制GaN功率放大器的电源开关
热门文章
- 表单中的重置与取消按钮
- ubuntu下载gmt_科学网—Linux/Ubuntu安装地学制图软件GMT6.0.0 - 杨家乐的博文
- 实现根据条件删除_强大的定位空值法,1秒删除所有不想要的数据
- 新海诚没有参与制作的作品_新海诚简介和所有作品列表
- linux下载python的地址_Linux下Python获取IP地址的代码
- python cv release_cv2.videoCapture.release()是什么意思?
- vue4 跳转外部链接_vue跳转到外部链接
- 想要酷炫大气的网页设计?这样做超吸睛
- 设计灵感|如何做好网页后台数据展示的设计?
- 不规则炫彩创意渐变海报设计模板素材|带来十足的时尚感