当前位置:网站首页>十一、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()边栏推荐
猜你喜欢
随机推荐
5V升压充电8.4V芯片
什么是数据安全性?
Xshell 7 prompts "To continue using this program, you must apply the latest update or use a new version"
【Verilog】Verilog设计进阶
解决reudx中的异步问题 applyMiddleware thunk
【板栗糖GIS】wps—如何查看表格中的超链接
[Point Cloud] M3DeTR: Multi-representation, Multi-scale, Mutual-relation 3D Object Detection with Transformers
数组和List互转
【点云】M3DeTR: Multi-representation, Multi-scale, Mutual-relation 3D Object Detection with Transformers
刚重装的win7系统不能上网(深度系统安装步骤)
Second Best PyTorch Beginner Course; Thesis Writing Guide; Using µGo to Develop a Mini Compiler; Super Efficient Use of Transformer's Extension Library; Frontier Papers | ShowMeAI News Daily
在Ferora35中安装oracle-database-xe-21c
leetcode122. Best Time to Buy and Sell Stock II 买卖股票的最佳时机 II(简单)
啊?现在初级测试招聘都要求会自动化了?
对不起,你很难赚到中年人的钱
系列(jupyter自动保存失败)
D. Rain(思维/线性代数/差分数组)
linux使用脚本安装redis
24小时伦敦金走势图分析
网络通信编程基础,BIO,NIO








