主流Java數(shù)據(jù)庫連接池分析(C3P0,DBCP,TomcatPool,BoneCP,Druid)
主流數(shù)據(jù)庫連接池
常用的主流開源數(shù)據(jù)庫連接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等
C3p0: 開源的JDBC連接池,實(shí)現(xiàn)了數(shù)據(jù)源和JNDI綁定,支持JDBC3規(guī)范和JDBC2的標(biāo)準(zhǔn)擴(kuò)展。目前使用它的開源項(xiàng)目有Hibernate、Spring等。單線程,性能較差,適用于小型系統(tǒng),代碼600KB左右。
DBCP (Database Connection Pool):由Apache開發(fā)的一個Java數(shù)據(jù)庫連接池項(xiàng)目, Jakarta commons-pool對象池機(jī)制,Tomcat使用的連接池組件就是DBCP。單獨(dú)使用dbcp需要3個包:common-dbcp.jar,common-pool.jar,common-collections.jar,預(yù)先將數(shù)據(jù)庫連接放在內(nèi)存中,應(yīng)用程序需要建立數(shù)據(jù)庫連接時直接到連接池中申請一個就行,用完再放回。單線程,并發(fā)量低,性能不好,適用于小型系統(tǒng)。
Tomcat Jdbc Pool:Tomcat在7.0以前都是使用common-dbcp做為連接池組件,但是dbcp是單線程,為保證線程安全會鎖整個連接池,性能較差,dbcp有超過60個類,也相對復(fù)雜。Tomcat從7.0開始引入了新增連接池模塊叫做Tomcat jdbc pool,基于Tomcat JULI,使用Tomcat日志框架,完全兼容dbcp,通過異步方式獲取連接,支持高并發(fā)應(yīng)用環(huán)境,超級簡單核心文件只有8個,支持JMX,支持XA Connection。
BoneCP:官方說法BoneCP是一個高效、免費(fèi)、開源的Java數(shù)據(jù)庫連接池實(shí)現(xiàn)庫。設(shè)計(jì)初衷就是為了提高數(shù)據(jù)庫連接池性能,根據(jù)某些測試數(shù)據(jù)顯示,BoneCP的速度是最快的,要比當(dāng)時第二快速的連接池快25倍左右,完美集成到一些持久化產(chǎn)品如Hibernate和DataNucleus中。BoneCP特色:高度可擴(kuò)展,快速;連接狀態(tài)切換的回調(diào)機(jī)制;允許直接訪問連接;自動化重置能力;JMX支持;懶加載能力;支持XML和屬性文件配置方式;較好的Java代碼組織,100%單元測試分支代碼覆蓋率;代碼40KB左右。
Druid:Druid是Java語言中最好的數(shù)據(jù)庫連接池,Druid能夠提供強(qiáng)大的監(jiān)控和擴(kuò)展功能,是一個可用于大數(shù)據(jù)實(shí)時查詢和分析的高容錯、高性能的開源分布式系統(tǒng),尤其是當(dāng)發(fā)生代碼部署、機(jī)器故障以及其他產(chǎn)品系統(tǒng)遇到宕機(jī)等情況時,Druid仍能夠保持100%正常運(yùn)行。主要特色:為分析監(jiān)控設(shè)計(jì);快速的交互式查詢;高可用;可擴(kuò)展;Druid是一個開源項(xiàng)目,源碼托管在github上。
主流連接池各項(xiàng)功能對比如下:
我們再看一組有HikariCP的
HikariCP性能分析:
-
HikariCP通過優(yōu)化(concurrentBag,fastStatementList )集合來提高并發(fā)的讀寫效率。
-
HikariCP使用threadlocal緩存連接及大量使用CAS的機(jī)制,最大限度的避免lock。單可能帶來cpu使用率的上升。
-
從字節(jié)碼的維度優(yōu)化代碼。 (default inline threshold for a JVM running the server Hotspot compiler is 35 bytecodes )讓方法盡量在35個字節(jié)碼一下,來提升jvm的處理效率。
HikariCP做的優(yōu)化補(bǔ)充如下:
mysql connecter 源碼里用的就是ping命令
比HikariCP更快的數(shù)據(jù)庫連接池
一個同事告訴我,比hikari還快的連接池他也用過、研究過 https://github.com/mauricio/postgresql-async 這是scala生態(tài)圈的東西。用netty實(shí)現(xiàn)了mysql協(xié)議,沒用mysql官方的connector,純異步的,它的連接池是寫的比較隨便,但是性能依然很好。
前瞻,未來到底是HikariCP還是Druid的天下?
很多人都在問,站在巨人肩膀上的第二代連接池HikariCP和druid到底孰強(qiáng)孰弱?其實(shí)我覺得這是一個不必討論的問題。
我們先來看看未來的趨勢:單機(jī)的操作系統(tǒng)將會被拋棄,取而代之的是容器調(diào)度加編排的云操作系統(tǒng)。裸機(jī)或者虛擬機(jī)的運(yùn)行時也將會被容器取代。通信方面將會使用Service Mesh。
也就是說中間件最后的趨勢一定是弱化到無感知,這才是最終的一個大道至簡的方向。那些maven依賴問題,把二方庫寫在pom里,監(jiān)控等代碼的硬編碼進(jìn)應(yīng)用里都將逐漸弱化到不復(fù)存在,取而代之的那些java agent(如pinpoint、skywalking之類),抑或是service mesh這種side car模式都是可以做中間件(包括連接池)的監(jiān)控的。
一個有贊的朋友告訴我,在有贊核心應(yīng)用,用HikariCP替換durid后,RT出現(xiàn)斷崖式下滑(1.5ms ~ 1.2ms) 并且持續(xù)穩(wěn)定毛刺少。性能測試與壓測之后,一核心系統(tǒng)與druid相比,性能提高一倍左右。
阿飛做了如下統(tǒng)計(jì)工作,都是基于最新tag統(tǒng)計(jì)的,只統(tǒng)計(jì)java文件和xml文件,druid(alibaba-druid)總行數(shù):430289,HikariCP(brettwooldridge-HikariCP)總行數(shù):18372。 只統(tǒng)計(jì)java代碼,druid(alibaba-druid)總行數(shù):428749,HikariCP(brettwooldridge-HikariCP)總行數(shù):17556。 再過濾一下test目錄,(alibaba-druid)總行數(shù):215232,(brettwooldridge-HikariCP)總行數(shù):7960。 光一個DruidDataSource就3000行,且不說性能,druid是在jdbc的基礎(chǔ)上,自己編碼做得增強(qiáng)。
如果這么說,druid準(zhǔn)確的說是生活在第一代和第二代連接池的面向過程的年代。druid可能忘了松耦合這個概念,把監(jiān)控和數(shù)據(jù)庫連接池做在一個項(xiàng)目里,本身就是緊耦合。既然微服務(wù)提倡業(yè)務(wù)隔離性,那么這種難道不應(yīng)該隔離么?讓組件工具一次只做一件事不好么?監(jiān)控的事情在service mesh的將來畢竟是有別的其天然的監(jiān)控手法的而不是硬編碼在一個小小的連接池里。綜上所述,放在現(xiàn)在或是未來的趨勢去拼,大概率比不過擁抱springboot 2.0以及大道至簡精簡到極致的HikariCP。
未來的中間件,一定是和spring生態(tài)圈和servich mesh一樣,大道至簡,越來越薄,升級中間件不再是需要用戶強(qiáng)行升級maven依賴解決依賴沖突,而是通過mesh的方式極致到升級讓業(yè)務(wù)方無感知。所以那些熱部署、潘多拉boot、容器隔離等解決依賴沖突的妥協(xié)方式也將可能大概率被置換掉。
從Sharding-jdbc架構(gòu)演進(jìn)看未來
Database Mesh,一個搭乘 Service Mesh 浪潮衍生出來的新興詞匯。顧名思義,Database Mesh 使用一個嚙合層,將散落在系統(tǒng)各個角落中的數(shù)據(jù)庫統(tǒng)一治理起來。通過嚙合層集中在一起的應(yīng)用與數(shù)據(jù)庫之間的交互網(wǎng)絡(luò),就像蜘蛛網(wǎng)一樣復(fù)雜而有序。它的首要目標(biāo)并非嚙合存儲于數(shù)據(jù)庫中的數(shù)據(jù),而是嚙合應(yīng)用與數(shù)據(jù)庫間的交互。
Database Mesh 的關(guān)注重點(diǎn)在于如何將分布式的數(shù)據(jù)訪問應(yīng)用與數(shù)據(jù)庫有機(jī)串聯(lián)起來,它更加關(guān)注的是交互,是將雜亂無章的應(yīng)用與數(shù)據(jù)庫之間的交互有效的梳理。
使用 Database Mesh,訪問數(shù)據(jù)庫的應(yīng)用和數(shù)據(jù)庫終將形成一個巨大的網(wǎng)格體系,應(yīng)用和數(shù)據(jù)庫只需在網(wǎng)格體系中對號入座即可,它們都是被嚙合層所治理的對象。
Sharding-JDBC 一直以來,以 JDBC 層分片作為其核心理念。它的架構(gòu)圖如下:
Sharding-JDBC 將分別實(shí)現(xiàn) Driver、Server 以及 Sidecar 這三個不同的版本,一起組成 Sharding-JDBC 的生態(tài)圈,為不同的需求與環(huán)境提供更加具有針對性的差異化服務(wù)。
由于 Sharding-JDBC-Server 的出現(xiàn),使得原來 DBA 通過 Sharding-JDBC-Driver 無法對數(shù)據(jù)進(jìn)行操作的缺憾得到了補(bǔ)償。由于 Sharding-JDBC-Driver 無需通過代理層進(jìn)行二次轉(zhuǎn)發(fā),因此線上性能更佳,可以通過以下的混合部署方案使用 Sharding-JDBC:
線上應(yīng)用使用 Sharding-JDBC-Driver 直連數(shù)據(jù)庫以獲取最優(yōu)性能,使用 MySQL 命令行或 UI 客戶端連接 Sharding-JDBC-Server 方便的查詢數(shù)據(jù)和執(zhí)行各種 DDL 語句。它們使用同一個注冊中心集群,通過管理端配置注冊中心中的數(shù)據(jù),即可由注冊中心自動將配置變更推送至 Driver 和 Server 應(yīng)用。若數(shù)據(jù)庫拆分的過多而導(dǎo)致連接數(shù)會暴漲,則可以考慮直接在線上使用 Sharding-JDBC-Server,以達(dá)到有效控制連接數(shù)的目的。
在不久的將來,Sharding-JDBC-Sidecar 也將問世,它的部署架構(gòu)是這樣的:
基于 Sharding-JDBC 的 Database Mesh 與 Service Mesh 互不干擾,相得益彰。服務(wù)之間的交互由 Service Mesh Sidecar 接管,基于 SQL 的數(shù)據(jù)庫訪問由 Sharding-JDBC-Sidecar 接管。
對于業(yè)務(wù)應(yīng)用來說,無論是 RPC 還是對數(shù)據(jù)庫的訪問,都無需關(guān)注其真實(shí)的物理部署結(jié)構(gòu),做到真正的零侵入。由于 Sharding-JDBC-Sidecar 是隨著宿主機(jī)的生命周期創(chuàng)建和消亡的,
因此,它并非靜態(tài) IP,而是完全動態(tài)和彈性的存在,整個系統(tǒng)中并無任何中心節(jié)點(diǎn)的存在。對于數(shù)據(jù)運(yùn)維等操作,仍然可以通過啟動一個 Sharding-JDBC-Server 的進(jìn)程作為靜態(tài) IP 的入口,通過各種命令行或 UI 客戶端進(jìn)行操作。