天天看點

一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結

一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結

前言

本章是HikariCP的最後一章,學習HikariCP如何設計歸還連接配接和關閉連接配接。

一、歸還連接配接

一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結

因為暴露給使用者使用的是Connection的代理對象

HikariProxyConnection

,使用者調用

close

方法關閉連接配接,實際執行的是

ProxyConnection#close

歸還連接配接。

PoolEntry#recycle

HikariPool#recycle

将PoolEntry歸還給ConcurrentBag。

private final ConcurrentBag connectionBag;@Overridevoid recycle(final PoolEntry poolEntry) {
   connectionBag.requite(poolEntry);
}
           

ConcurrentBag#requite

修改Entry狀态。

Hikari連接配接池如何實作借走和歸還?

一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結
一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結
  • PoolEntry包裝Connection被放入ConcurrentBag
  • 使用者借走通過PoolEntry構造的ProxyConnection
  • 使用中…
  • ProxyConnection.close修改ProxyConnection裡的委托對象為CLOSED_CONNECTION,拒絕使用者後續操作
  • PoolEntry修改狀态,歸還給ConcurrentBag,PoolEntry就可以被其他人借走了

二、關閉連接配接

一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結

HouseKeeper

The house keeping task to retire and maintain minimum idle connections.

HouseKeeper

實作Runnable接口,負責執行連接配接過期并維持最小空閑連接配接。HikariCP啟動的過程中,HouseKeeper是在HikariPool構造時送出到線程池定期執行的。預設30秒執行一次,可以通過配置

com.zaxxer.hikari.housekeeping.periodMs

系統參數修改。

HouseKeeper

一個定時任務執行了很多事情。

1. JMX運作時修改配置,更新HikariPool的一些成員變量

2. 檢測時鐘倒退

previous

代表上次執行的時間戳,

housekeepingPeriodMs

預設30秒。正常情況下

now = previous + housekeepingPeriodMs

,如果

previous + housekeepingPeriodMs - now > 128

發生時鐘倒退超過128ms,則執行

softEvictConnections

軟驅逐所有連接配接,并直接傳回。

HikariPool#softEvictConnections

首先

poolEntry.markEvicted()

将PoolEntry标記為被驅逐,如果之後的操作沒成功,這個連接配接将在下次getConnection的時候被檢測到驅逐,進而關閉。

判斷調用者是否是

owner

,即是否是使用者。如果是使用者自己操作

HikariPool#evictConnection

方法驅逐連接配接,關閉連接配接(見3)。

執行

connectionBag.reserve(poolEntry)

,将PoolEntry的狀态通過CAS從

STATE_NOT_IN_USE

修改為

STATE_RESERVED

狀态,如果執行成功,關閉連接配接(見3)。

3. 關閉空閑連接配接

@Override
public void run() {
  // ...
  if (idleTimeout > 0L && config.getMinimumIdle()      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--;
        }
     }
  }// ...
}
           

首先判斷目前配置

idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()

是否支援空閑連接配接逾時關閉。要設定

idleTimeout

并且

MinimumIdle

要小于

MaximumPoolSize

接下來計算總共有多少連接配接需要關閉。待關閉數量(

toRemove

)=

STATE_NOT_IN_USE

的PoolEntry總數 - 配置的

MinimumIdle

數量。

循環所有未使用的PoolEntry,判斷 目前時間 - entry的上次使用時間 是否大于

idleTimeout

,并且執行

reserve

修改PoolEntry狀态成功。如果修改成功,執行關閉連接配接。

HikariPool#closeConnection

是關閉連接配接的公共入口。

connectionBag.remove(poolEntry)

修改PoolEntry狀态,從shareList和threadList中移除這個元素。

poolEntry.close()

關閉MaxLifeTime逾時檢測任務,一些變量賦空值幫助GC。

準備工作都做好以後,把關閉任務送出到線程池,執行關閉連接配接。如果連接配接池仍然是正常狀态(

POOL_NORMAL

),嘗試維持最小空閑連接配接(

fillPool()

見4)。

4. 維持最小空閑連接配接

業務上往往我們稱Hikari連接配接池的

MinimumIdle

為最小連接配接數,其實這是一個簡稱,全稱是

最小空閑連接配接數

。它是保證連接配接池中至少有x個連接配接是空閑的,拿來即可用,但是需要保證總連接配接數不會超過

MaximumPoolSize

首先計算需要添加多少連接配接。缺少最大連接配接和缺少空閑連接配接取小,扣除目前正在準備建立的連接配接(

addConnectionQueueReadOnlyView.size()

是線程池

addConnectionExecutor

的等待隊列視圖),就是

connectionsToAdd

需要建立的連接配接。

例如:配置MaximumPoolSize=10,MinimumIdle=5;此時總連接配接數=7,空閑連接配接數=4,等待建立連接配接線程數=0。根據公式計算:

Math.min(10 - 7, 5 - 4) - 0 = 1

,還需要建立一個連接配接,因為空閑連接配接數不夠5。如果按照最小連接配接數去了解,這裡應該不需要建立連接配接了,因為連接配接數已經有7個了。

最後把建立連接配接的任務送出到

addConnectionExecutor

執行。

HikariPool#getConnection

getConnection

方法在第四章介紹過,主要是擷取PoolEntry,并建立ProxyConnection給使用者使用。

注意當

poolEntry.isMarkedEvicted()

PoolEntry被标記未驅逐,或

!isConnectionAlive(poolEntry.connection)

連接配接存活檢測不通過時,會執行

closeConnection

關閉連接配接,關閉連接配接方法在上面講過。

MaxLifetime到期軟驅逐

當一個連接配接被建立之後,就會開啟一個延遲任務,檢測連接配接如果超過MaxLifetime則進行軟驅逐(

softEvictConnection

)。代碼見

HikariPool#createPoolEntry

方法。

連接配接池關閉

HikariDataSource#close

修改isShutdown狀态。

HikariPool#shutdown

關閉所有線程池,取消所有任務,關閉所有資料庫連接配接。

abortActiveConnections

中斷所有正在使用的連接配接,并将PoolEntry從connectionBag移除。

為什麼需要多次執行

abortActiveConnections

softEvictConnections

,直到

getTotalConnections<0

因為PoolEntry的狀态時刻發生變化,不多次嘗試可能導緻少關閉連接配接。

abortActiveConnections

隻負責

STATE_IN_USE

的PoolEntry;

softEvictConnections

隻負責

STATE_NOT_IN_USE

的PoolEntry。

總結

關于歸還連接配接,對于HikariCP如何設計連接配接借走和歸還有一個整體的了解,主要利用了代理和ConcurrentBag。

對于關閉連接配接,觸發點很多,一般都是通過軟驅逐或強制關閉兩種方式關閉。重點關注HouseKeeper這個30秒定時任務的作用。

原創不易,歡迎評論、點贊和關注。歡迎關注公衆号:程式猿阿越。
一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結
一連接配接伺服器sftp就顯示 connection closed_HikariCP源碼閱讀(五)歸還與關閉連接配接前言一、歸還連接配接二、關閉連接配接總結