序
本文主要研究一下hikari连接池的maxLifetime属性及evict操作
maxLifetime属性及evict操作
maxLifetime
用来设置一个connection在连接池中的存活时间,默认是,即30分钟。如果设置为0,表示存活时间无限大。如果不等于0且小于30秒则会被重置回30分钟。
evict
用来标记连接池中的连接不可用,这样在borrow连接的时候,如果是标记evict的,则会继续获取连接
/ * Get a connection from the pool, or timeout after the specified number of milliseconds. * * @param hardTimeout the maximum time to wait for a connection from the pool * @return a java.sql.Connection instance * @throws SQLException thrown if a timeout occurs trying to obtain a connection */ public Connection getConnection(final long hardTimeout) throws SQLException { suspendResumeLock.acquire(); final long startTime = currentTime(); try { long timeout = hardTimeout; do { PoolEntry poolEntry = connectionBag.borrow(timeout, MILLISECONDS); if (poolEntry == null) { break; // We timed out... break and throw exception } final long now = currentTime(); if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) { closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE); timeout = hardTimeout - elapsedMillis(startTime); } else { metricsTracker.recordBorrowStats(poolEntry, startTime); return poolEntry.createProxyConnection(leakTaskFactory.schedule(poolEntry), now); } } while (timeout > 0L); metricsTracker.recordBorrowTimeoutStats(startTime); throw createTimeoutException(startTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new SQLException(poolName + " - Interrupted during connection acquisition", e); } finally { suspendResumeLock.release(); } } 复制代码
讯享网
注意,这里如果取到的连接是poolEntry.isMarkedEvicted(),则会close掉,同时更新timeout值,然后继续循环borrow连接
HikariPool.evictConnection
HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java
讯享网 / * Evict a Connection from the pool. * * @param connection the Connection to evict (actually a {@link ProxyConnection}) */ public void evictConnection(Connection connection) { ProxyConnection proxyConnection = (ProxyConnection) connection; proxyConnection.cancelLeakTask(); try { softEvictConnection(proxyConnection.getPoolEntry(), "(connection evicted by user)", !connection.isClosed() /* owner */); } catch (SQLException e) { // unreachable in HikariCP, but we're still forced to catch it } } 复制代码
这种是主动调用evictConnection的场景
HikariPool.createPoolEntry
HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java
/ * 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; } } / * "Soft" evict a Connection (/PoolEntry) from the pool. If this method is being called by the user directly * through {@link com.zaxxer.hikari.HikariDataSource#evictConnection(Connection)} then {@code owner} is {@code true}. * * If the caller is the owner, or if the Connection is idle (i.e. can be "reserved" in the {@link ConcurrentBag}), * then we can close the connection immediately. Otherwise, we leave it "marked" for eviction so that it is evicted * the next time someone tries to acquire it from the pool. * * @param poolEntry the PoolEntry (/Connection) to "soft" evict from the pool * @param reason the reason that the connection is being evicted * @param owner true if the caller is the owner of the connection, false otherwise * @return true if the connection was evicted (closed), false if it was merely marked for eviction */ private boolean softEvictConnection(final PoolEntry poolEntry, final String reason, final boolean owner) { poolEntry.markEvicted(); if (owner || connectionBag.reserve(poolEntry)) { closeConnection(poolEntry, reason); return true; } return false; } 复制代码
注意在createPoolEntry的时候注册了一个延时任务,并通过poolEntry.setFutureEol设置到poolEntry中
softEvictConnection,首先标记markEvicted。然后如果是用户自己调用的,则直接关闭连接;如果从connectionBag中标记不可borrow成功,则关闭连接
这个定时任务是在每次createPoolEntry的时候,根据maxLifetime随机设定一个variance,在maxLifetime - variance之后触发evict
小结
hikari连接池的maxLifetime用来标记connection在连接池中的存活时间,为0表示无限期。其到期的操作,主要是依靠在创建poolEntry的时候,注册一个延时任务,在连接存活将要到达maxLifetime之前触发evit,用来防止出现大面积的connection因maxLifetime同一时刻失效。除了这个延时任务,用户也可以主动去调用evict标记连接为evict。
触发时间距离maxlifetime的差值是根据 maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0; 来计算(up to 2.5% of the maxlifetime)。
标记为evict只是表示连接池中的该连接不可用,但还在连接池当中,还会被borrow出来,只是getConnection的时候判断了,如果是isMarkedEvicted,则会从连接池中移除该连接,然后close掉。
doc
- configuration-knobs-baby

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/71855.html