问题:
2020-03-18 09:44:03.404 WARN 10900 --- [datasource housekeeper] com.zaxxer.hikari.pool.HikariPool : datasource - Thread starvation or clock leap detected (housekeeper delta=10m28s381ms837µs874ns).
分析:
WARN
, 警告级别,看起来不是什么错误,但是连接数据库就是连不上
英译汉:数据源-检测到线程饥饿或时钟跳动
人话:要么是检测到等待连接的时间过长,造成进饥饿;要么是检测到时钟跳动,反正最后是关闭了数据库连接。
看了看我的数据库连接池配置,并没有使用hikari, 应该是springboot默认的方式
datasource:
name: datasource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${ip}:3306/${数据库}?useSSL=false&characterEncoding=UTF-8
username: ${username}
password: ${password}
这里说一下hikari连接池吧:
hikari, 号称最快连接池,光速嘛,springboot 2.x 默认数据库连接池。
顺便找找源码中有没有日志的警告:
public void run()
{
try {
// refresh values in case they changed via MBean
connectionTimeout = config.getConnectionTimeout();
validationTimeout = config.getValidationTimeout();
leakTaskFactory.updateLeakDetectionThreshold(config.getLeakDetectionThreshold());
catalog = (config.getCatalog() != null && !config.getCatalog().equals(catalog)) ? config.getCatalog() : catalog;
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<PoolEntry> 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);
}
}
now > plusMillis(previous, (3 * HOUSEKEEPING_PERIOD_MS) / 2)
No point evicting for forward clock motion, this merely accelerates connection retirement anyway
英译汉: 没有任何必要将时钟向前移动,这只会加速连接的退出
来看看连接被移除的几种情况:
HouseKeeper是一项30s周期的检测任务,
- 时钟倒退,驱逐连接; (此处需要结合案列)
- 驱逐超出idle-timeout时间的空闲连接,
解决:
使用自定义hikari配置,
并设置以下参数
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${ip}:3306/${数据库}?useSSL=false&characterEncoding=UTF-8
username: ${username}
password: ${password}
hikari:
auto-commit: true
#空闲连接超时时长
idle-timeout: 60000
#连接超时时长
connection-timeout: 60000
#最大生命周期,0不过期
max-lifetime: 0
#最小空闲连接数
minimum-idle: 10
#最大连接数量
maximum-pool-size: 10