分析springboot2.0自帶連接池HikariCP的優勢

HiKariCP是數據庫連接池的一個後起之秀,號稱性能最好,可以完美地PK掉其他連接池,是一個高性能的JDBC連接池,基於BoneCP做了不少的改進和優化。其作者還有另外一個開源作品——高性能的JSON解析器HikariJSON。

Springboot 2.0選擇HikariCP作爲默認數據庫連接池的五大理由

 

從以上圖可看出Hikari相比起其它連接池的性能高了非常多,那麼,這麼好的是怎麼做到的呢?官網詳細地說明了HikariCP所做的一些優化,總結如下:

  • 字節碼精簡 :優化代碼,直到編譯後的字節碼最少,這樣,CPU緩存可以加載更多的程序代碼;
  • 優化代理和攔截器:減少代碼,例如HikariCP的Statement proxy只有100行代碼,只有BoneCP的十分之一;
  • 自定義數組類型(FastStatementList)代替ArrayList:避免每次get()調用都要進行range check,避免調用remove()時的從頭到尾的掃描(由於連接的特點是後獲取連接的先釋放);
  • 自定義集合類型(ConcurrentBag:提高併發讀寫的效率;
  • 其他針對BoneCP缺陷的優化,比如對於耗時超過一個CPU時間片的方法調用的研究。

 

1、代碼量精簡比較:

2、第三方關於速度的測試:

Springboot 2.0選擇HikariCP作爲默認數據庫連接池的五大理由

3、軟件穩定性

Springboot 2.0選擇HikariCP作爲默認數據庫連接池的五大理由

4、可靠性

另外,關於可靠性方面,也是有實驗和數據支持的。對於數據庫連接中斷的情況,通過測試getConnection(),各種CP的不相同處理方法如下:

(所有CP都配置了跟connectionTimeout類似的參數爲5秒鐘)

  • HikariCP:等待5秒鐘後,如果連接還是沒有恢復,則拋出一個SQLExceptions 異常;後續的getConnection()也是一樣處理;
  • C3P0:完全沒有反應,沒有提示,也不會在“CheckoutTimeout”配置的時長超時後有任何通知給調用者;然後等待2分鐘後終於醒來了,返回一個error;
  • Tomcat:返回一個connection,然後……調用者如果利用這個無效的connection執行SQL語句……結果可想而知;大約55秒之後終於醒來了,這時候的getConnection()終於可以返回一個error,但沒有等待參數配置的5秒鐘,而是立即返回error;
  • BoneCP:跟Tomcat的處理方法一樣;也是大約55秒之後才醒來,有了正常的反應,並且終於會等待5秒鐘之後返回error了;

5、HikariCP源代碼分析

1、首先,HikariCP利用了一個第三方的Java字節碼修改類庫Javassist來生成委託實現動態代理。動態代理的實現在ProxyFactory類之所以使用Javassist生成動態代理,是因爲其速度更快,相比於JDK Proxy生成的字節碼更少,精簡了很多不必要的字節碼。

代理工廠類

 

2、其次,單獨寫了一個併發類-ConcurrentBag,ConcurrentBag的實現借鑑於C#中的同名類,是一個專門爲連接池設計的lock-less集合,實現了比LinkedBlockingQueue、LinkedTransferQueue更好的併發性能。

ConcurrentBag類

ProxyConnection代理連接類

ConcurrentBag內部同時使用了ThreadLocal和CopyOnWriteArrayList來存儲元素,其中CopyOnWriteArrayList是線程共享的。ConcurrentBag採用了queue-stealing的機制獲取元素:首先嚐試從ThreadLocal中獲取屬於當前線程的元素來避免鎖競爭,如果沒有可用元素則再次從共享的CopyOnWriteArrayList中獲取。此外,ThreadLocal和CopyOnWriteArrayList在ConcurrentBag中都是成員變量,線程間不共享,避免了僞共享(false sharing)的發生

3、使用FastList替代ArrayList

1、FastList是一個List接口的精簡實現,只實現了接口中必要的幾個方法。

2、JDK ArrayList每次調用get()方法時都會進行rangeCheck檢查索引是否越界,FastList的實現中去除了這一檢查,只要保證索引合法那麼rangeCheck就成爲了不必要的計算開銷(當然開銷極小)。

3、此外,HikariCP使用List來保存打開的Statement,當Statement關閉或Connection關閉時需要將對應的Statement從List中移除。通常情況下,同一個Connection創建了多個Statement時,後打開的Statement會先關閉。ArrayList的remove(Object)方法是從頭開始遍歷數組,而FastList是從數組的尾部開始遍歷,因此更爲高效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章