当前位置:网站首页>十一、HikariCP源码分析之HouseKeeper
十一、HikariCP源码分析之HouseKeeper
2022-07-29 21:41:00 【InfoQ】
HikariPoolRunnableScheduledThreadPoolExecutorhouseKeepingExecutorService/**
* HouseKeeper用于空闲连接过期
*/
private class HouseKeeper implements Runnable {
private volatile long previous = clockSource.plusMillis(clockSource.currentTime(), -HOUSEKEEPING_PERIOD_MS);
@Override
public void run() {
//①
//刷新通过MBean修改的设置
connectionTimeout = config.getConnectionTimeout();
validationTimeout = config.getValidationTimeout();
leakTask.updateLeakDetectionThreshold(config.getLeakDetectionThreshold());
//②
final long idleTimeout = config.getIdleTimeout();
final long now = clockSource.currentTime();
//检测时间回拨, 即网络对时服务对时钟的调整, 允许 128 毫秒的时间差
if (clockSource.plusMillis(now, 128) < clockSource.plusMillis(previous, HOUSEKEEPING_PERIOD_MS)) {
LOGGER.warn("{} - Retrograde clock change detected (housekeeper delta={}), soft-evicting connections from pool.",
clockSource.elapsedDisplayString(previous, now), poolName);
previous = now;
//连接池中所以的连接都标记删除
softEvictConnections();
//重新创建连
fillPool();
return;
} else if (now > clockSource.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={}).", clockSource.elapsedDisplayString(previous, now), poolName);
}
//原来的实现代码如下文件的633-650 行: https://github.com/brettwooldridge/HikariCP/blob/bc010fba486b27ae3d034cc9701e0c4217457ddb/src/main/java/com/zaxxer/hikari/pool/HikariPool.java
// logPoolState("Before cleanup ");
// for (PoolBagEntry bagEntry : connectionBag.values(STATE_NOT_IN_USE)) {
// if (connectionBag.reserve(bagEntry)) {
// if (bagEntry.evicted) {
// closeConnection(bagEntry, "(connection evicted)");
// }
// else if (idleTimeout > 0L && clockSource.elapsedMillis(bagEntry.lastAccess, now) > idleTimeout) {
// closeConnection(bagEntry, "(connection passed idleTimeout)");
// }
// else {
// connectionBag.unreserve(bagEntry);
// }
// }
// }
//
// logPoolState("After cleanup ");
//
// fillPool(); // Try to maintain minimum connections
// }
// 代码中, 先将所有超过空闲时间的连接都关闭, 然后将连接池中的连接再填充到minIdle最小空闲连接数
// 后来有个名为 yaojuncn 的人跟brett提了个 issue, 如下: https://github.com/brettwooldridge/HikariCP/issues/379
// issue的内容就是yaojuncn发现, 清理空闲连接的时候, 连接数会小于minIdle, 极端情况下会是 0, 他认为这样有问题, 服务请求多的时候, 会大量的创建连接, 给数据库造成压力
// 但是brett认为, 创建连接非常快, 极端情况的几率极小, 这不是个问题, 提议yaojuncn使用固定大小的连接池
// 讨论来讨论去, brett终于烦了, 接受了yaojuncn的建议, 并且合并了yaojuncn的 merge request.
// yaojuncn提的实现就是目前的请清理方式, 这个: https://github.com/yaojuncn/HikariCP/commit/cbb1e1cc93d050457ffe9939b67eacd6c6bd97a0
//③
//开始清理超过idleTimeout的空闲连接
previous = now;
String afterPrefix = "Pool ";
if (idleTimeout > 0L) {
//查出连接池中所有的空闲连接
final List<PoolEntry> idleList = connectionBag.values(STATE_NOT_IN_USE);
//空闲连接数量 - 用户配置的最小连接数 = 目前可以回收的连接数, 不明白详见Question①
int removable = idleList.size() - config.getMinimumIdle();
//如果有可以回收的连接
if (removable > 0) {
logPoolState("Before cleanup ");
afterPrefix = "After cleanup ";
// 按照最近访问的实际, 从小到大排序, 排序指标是最后访问时间的时间戳, 时间大的是最近使用的, 从小到大遍历比较合理, 能先清理掉长时间没用的, 不用遍历所有的空闲连接
//如果要清理的连接数够了,那么就不用继续遍历了,可以减少循环次数
Collections.sort(idleList, LAST_ACCESS_COMPARABLE);
for (PoolEntry poolEntry : idleList) {
//判断最后访问时间和当前时间的时间差, 是否超过了用户配置的最大空闲时间, 超过了就将连接变为保留状态
if (clockSource.elapsedMillis(poolEntry.lastAccessed, now) > idleTimeout && connectionBag.reserve(poolEntry)) {
//关闭连接
closeConnection(poolEntry, "(connection has passed idleTimeout)");
//可回收连接数减 1, 如果可回收连接数等于 0, 就是清理完了
if (--removable == 0) {
break; // keep min idle cons
}
}
}
}
}
//记录日志
logPoolState(afterPrefix);
//可能有些连接过期了, 重新填充连接池到用户配置的最小连接数
fillPool(); // Try to maintain minimum connections
}
}
①刷新配置
②时间回拨
idleTimeoutnowidleTimeoutnowclockSource.plusMillis(now, 128) < clockSource.plusMillis(previous, HOUSEKEEPING_PERIOD_MS)clockSource.plusMillis(now, 128)clockSourcepreviousHOUSEKEEPING_PERIOD_MS- 系统时间回退 128 毫秒以内
- 系统时间前进了,具体多长时间不管
previous = now;softEvictConnections();fillPool();③清理过期连接
connectionBag.values(STATE_NOT_IN_USE)int removable = idleList.size() - config.getMinimumIdle();removableCollections.sort(idleList, LAST_ACCESS_COMPARABLE);clockSource.elapsedMillis(poolEntry.lastAccessed, now) > idleTimeout && connectionBag.reserve(poolEntry)clockSource.elapsedMillis(poolEntry.lastAccessed, now)connectionBag.reserve(poolEntry)closeConnectionfillPool()边栏推荐
猜你喜欢
![[BUG]一个数组new的时候sizeof()忘乘上个数](/img/d7/fa821aee0626e715bbb4e422e7e2fb.png)
[BUG]一个数组new的时候sizeof()忘乘上个数

Docker 下 Oracle 安装与配置

Liu Genghong, boys and girls, come here!Sports data analysis and mining!(with a full set of code and data sets)

Numpy array processing (2)

《张卫国的夏天》欢乐来袭,黄磊、刘奕君携手演绎“冤种”兄弟

【板栗糖GIS】wps—如何查看表格中的超链接

【AD】【持续更新ing】关于AD设计过程中一些小细节

官宣!苏州吴江开发区上线电子劳动合同平台

GTK在drawable区域绘图

linux install redis using script
随机推荐
相亲信息
在Ferora35中安装oracle-database-xe-21c
GBASE 8s 数据库复合索引
【Verilog】Verilog设计进阶
【板栗糖GIS】arcmap—如何在表格空值处进行批量求和
爽朗的一天
sizeof和strlen的区别(strlen和sizeof的用法)
Xshell 7 提示 “要继续使用此程序,您必须应用最新的更新或使用新版本”
动态规划专题
网安学习-内网渗透2
jsonArray中按某字段排序
程序员「小镇做题」出身,月薪是父母半年收入 ……
【LeetCode】36、有效的数独
GBASE 8s 数据库的备份创建
The implementation of the flood control project and safety construction project in the flood storage and detention areas in Luluze and Ningjinbo was launched
第3章业务功能开发(线索关联市场活动,动态搜索)
leetcode-593:有效的正方形
官宣!苏州吴江开发区上线电子劳动合同平台
Liu Genghong, boys and girls, come here!Sports data analysis and mining!(with a full set of code and data sets)
银河麒麟V10 SP2 x86编译安装 PHP7.4