數據庫連接池概述
數據庫連接的建立是一種耗時、性能低、代價高的操作,頻繁的數據庫連接的建立和關閉極大的影響了系統的性能。數據庫連接池是系統初始化過程中創建一定數量的數據庫連接放於連接池中,當程序需要訪問數據庫時,不再建立一個新的連接,而是從連接池中取出一個已建立的空閒連接,使用完畢後,程序將連接歸還到連接池中,供其他請求使用,從而實現的資源的共享,連接的建立、斷開都由連接池自身來管理。
數據庫連接池爲系統的運行帶來了以下優勢:
昂貴的數據庫連接資源得到重用;減少了數據庫連接建立和釋放的時間開銷,提高了系統響應速度;統一的數據庫連接管理,避免了連接資源的泄露。
數據庫連接池運行機制:
系統初始化時創建連接池,程序操作數據庫時從連接池中獲取空閒連接,程序使用完畢將連接歸還到連接池中,系統退出時,斷開所有數據庫連接並釋放內存資源。
背景
對現有的數據庫連接池做調研對比,綜合性能,可靠性,穩定性,擴展性等因素選出推薦出最優的數據庫連接池 。
各大連接池功能對比
功能 | dbcp | druid | c3p0 | tomcat-jdbc | HikariCP |
---|---|---|---|---|---|
是否支持PSCache | 是 | 是 | 是 | 否 | 否 |
監控 | jmx | jmx/log/http | jmx,log | jmx | jmx |
擴展性 | 弱 | 好 | 弱 | 弱 | 弱 |
sql攔截及解析 | 無 | 支持 | 無 | 無 | 無 |
代碼 | 簡單 | 中等 | 複雜 | 簡單 | 簡單 |
更新維護 | 否 | 是 | 否 | 否 | 是 |
特點 | 依賴於common-pool | 阿里開源,功能全面 | 歷史久遠,代碼邏輯複雜,且不易維護 | 優化力度大,功能簡單,起源於boneCP | |
連接池管理 | LinkedBlockingDeque | 數組、CopyOnWriteArrayList(COW) | 隊列 | FairBlockingQueue | threadlocal+CopyOnWriteArrayList |
是否開源 | 是 | 是 | 是 | 是 | 是 |
- 由於boneCP被hikariCP替代,並且已經不再更新,boneCP沒有進行調研。
- proxool網上有評測說在併發較高的情況下會出錯,proxool便沒有進行調研。
- druid的功能比較全面,且擴展性較好,比較方便對jdbc接口進行監控跟蹤等。
- c3p0歷史悠久,代碼及其複雜,不利於維護。並且存在死鎖的潛在風險。
性能測試
環境配置:
CPU | Intel® Xeon® CPU E5-2430 v2 @ 2.50GHz,24core |
---|---|
msyql 版本 | 5.5.46 |
tomcat-jdbc 版本 | 8.0.28 |
HikariCP 版本 | 2.4.3 |
c3p0 版本 | 0.9.5 |
dbcp版本 | 2.0.1 |
druid版本 | 1.0.5 |
1. 獲取關閉連接性能測試
測試說明:
- 初始連接和最小連接均爲5,最大連接爲20。在borrow和return均不心跳檢測
- 其中打開關閉次數爲: 100w次
- 測試用例和mysql在同一臺機器上面,儘量避免io的影響
- 使用mock和連接mysql在不同線程併發下的響應時間
圖形:
mock性能數據 (單位:ms)
5 | 20 | 50 | 100 | |
---|---|---|---|---|
tomcat-jdbc | 442 | 447 | 1,013 | 1,264 |
c3p0 | 4,480 | 5,527 | 7,449 | 10,725 |
dbcp | 676 | 689 | 867 | 1,292 |
hikari | 38 | 33 | 38 | 30 |
druid | 291 | 293 | 562 | 985 |
mysql性能數據 (單位:ms)
5 | 20 | 50 | 100 | |
---|---|---|---|---|
tomcat-jdbc | 436 | 453 | 1033 | 1291 |
c3p0 | 4378 | 5726 | 7975 | 10948 |
dbcp | 671 | 679 | 897 | 1380 |
hikari | 96 | 82 | 87 | 78 |
druid | 304 | 424 | 690 | 1130 |
測試結果:
- mock和mysql連接性能表現差不多,主要是由於初始化的時候建立了連接後期不再建立連接,和使用mock連接邏輯一致。
- 性能表現:hikariCP>druid>tomcat-jdbc>dbcp>c3p0。
- hikariCP 的性能及其優異。hikariCP號稱java平臺最快的數據庫連接池。
- hikariCP在併發較高的情況下,性能基本上沒有下降。
- c3p0連接池的性能很差,不建議使用該數據庫連接池。
hikariCP性能分析:
- hikariCP通過優化(concurrentBag,fastStatementList )集合來提高併發的讀寫效率。
- hikariCP使用threadlocal緩存連接及大量使用CAS的機制,最大限度的避免lock。單可能帶來cpu使用率的上升。
- 從字節碼的維度優化代碼。 (default inline threshold for a JVM running the server Hotspot compiler is 35 bytecodes )讓方法儘量在35個字節碼一下,來提升jvm的處理效率。
2.查詢一條語句性能測試
測試說明:
- 初始連接和最小連接均爲8,最大連接爲8。在borrow和return均不心跳檢測
- 查詢的次數爲10w次,查詢的語句爲 1:打開連接 2:執行 :select 1 ,3:關閉連接
- 測試用例和mysql在同一臺機器上面,儘量避免io的影響
圖形:
測試數據:
5 | 8 | 20 | 50 | 100 | |
---|---|---|---|---|---|
tomcat-jdbc | 2178 | 1495 | 1769 | 1818 | 1858 |
c3p0 | 3237 | 3451 | 4488 | 5994 | 7906 |
dbcp | 2816 | 1935 | 2097 | 2243 | 2280 |
hikari | 2299 | 1546 | 1682 | 1751 | 1772 |
druid | 2297 | 1551 | 1800 | 1977 | 2032 |
測試結果:
- 在併發比較少的情況下,每個連接池的響應時間差不多。是由於併發少,基本上沒有資源競爭。
- 在併發較高的情況下,隨着併發的升高,hikariCP響應時間基本上沒有變動。
- c3p0隨着併發的提高,性能急劇下降。
3:pscache性能對比
測試說明:
- 通過druid進行設置pscache和不設置pscache的性能對比
- 初始連接和最小連接均爲8,最大連接爲8。在borrow和return均不心跳檢測。並且執行的併發數爲8.
- 查詢10w次。查詢流程爲:1:建立連接,2:循環查詢preparestatement語句 3:close連接
- 測試用例和mysql在同一臺機器上面,儘量避免io的影響
測試數據:
cache | 1,927 |
---|---|
not cache | 2,134 |
測試結果:
- 開啓psCache緩存,性能大概有20%幅度的提升。可考慮開啓pscache.
測試說明:
- psCache是connection私有的,所以不存在線程競爭的問題,開啓pscache不會存在競爭的性能損耗。
- psCache的key爲prepare執行的sql和catalog等,value對應的爲prepareStatement對象。開啓緩存主要是減少了解析sql的開銷。
4: pscache詳解
druid的連接池配置中有PreparedStatementCache的配置,該信息解決了sql語句可以被預編譯,並且保存在PreparedStatement這個對象中,而這個對象的存儲就在PreparedStatementCache,對於oracle可以繞過數據庫編譯,有很大的提升,但是對於mysql,沒有那麼明顯。
這個值的設置不是越大越好,PSCache會佔用jvm,佔用量=連接數*PSCache設置的大小*每個PSCache佔用的內存。
測試結論
1:性能方面 hikariCP>druid>tomcat-jdbc>dbcp>c3p0 。hikariCP的高性能得益於最大限度的避免鎖競爭。
2:druid功能最爲全面,sql攔截等功能,統計數據較爲全面,具有良好的擴展性。
3:綜合性能,擴展性等方面,可考慮使用druid或者hikariCP連接池。
4:可開啓prepareStatement緩存,對性能會有大概20%的提升。