大話數(shù)據(jù)庫連接池

前言

數(shù)據(jù)庫連接池在Java數(shù)據(jù)庫相關(guān)中間件產(chǎn)品群中,應(yīng)該算是底層最基礎(chǔ)的一類產(chǎn)品,作為企業(yè)應(yīng)用開發(fā)必不可少的組件,無數(shù)天才們?yōu)槲覀冐暙I(xiàn)了一個(gè)又一個(gè)的優(yōu)秀產(chǎn)品,它們有的隨時(shí)代發(fā)展,功成身退,有的則還在不斷迭代,老而彌堅(jiān),更有新生代產(chǎn)品,或性能無敵,或功能全面。接下來,就讓我們好好聊聊,“那些年,我們用過的數(shù)據(jù)庫連接池”。

第一代連接池

區(qū)分一個(gè)數(shù)據(jù)庫連接池是屬于第一代產(chǎn)品還是第二代產(chǎn)品的一個(gè)最重要特征就是看它在架構(gòu)和設(shè)計(jì)時(shí)采用的線程模型,因?yàn)檫@直接影響的并發(fā)環(huán)境下存取數(shù)據(jù)庫連接的性能。一般來講采用單線程同步的架構(gòu)設(shè)計(jì)的都屬于第一代連接池,而采用多線程異步架構(gòu)的則屬于第二代。比較有代表性的就是Apache Commons DBCP,在1.x版本中,一直延續(xù)這單線程設(shè)計(jì)模型,到2.x版本才采用多線程模型。

用版本發(fā)布時(shí)間來辨別區(qū)分兩代產(chǎn)品,則一個(gè)偷懶的好方法。以下是這些常見數(shù)據(jù)庫連接池最新版本的發(fā)布時(shí)間:

數(shù)據(jù)庫連接池 最新版本 發(fā)布時(shí)間
c3p0 c3p0-0.9.5.2 on 9 Dec 2015
proxool 0.9.x May 24, 2011
dbcp 2.1.1 2015-08-06
BoneCP 0.8.0 on 23 Oct 2013
TJP tomcat9 Jan 10 2017
druid 1.0.28 2017-02-05
hikariCP 2.4.11 2017-01-28

從表中我們可以看到,c3p0、DBCP、Proxool和BoneCP都已經(jīng)很久沒更新了,TJP(Tomcat JDBC Pool),druid,hikariCPze則仍處于活躍的更新中,后者明顯就是我們所說的二代產(chǎn)品了。

已經(jīng)徹底死掉的c3p0和proxool

我對c3p0還是很有感情的,因?yàn)樵谒俏沂褂玫牡谝豢顢?shù)據(jù)庫連接池,在很長一段時(shí)間內(nèi),它一直是Java領(lǐng)域內(nèi)數(shù)據(jù)庫連接池的代名詞,當(dāng)年盛極一時(shí)的Hibernate都將其作為內(nèi)置的數(shù)據(jù)庫連接池,可見業(yè)內(nèi)對它的穩(wěn)定行還是認(rèn)可的。關(guān)于c3p0如何使用,可以借助于搜索引擎,這里就不再贅述了。c3p0功能簡單易用,穩(wěn)定性好這是它的優(yōu)點(diǎn),但性能上的缺點(diǎn)卻讓它徹底被打入冷宮。c3p0的性能很差,差到即便是和同時(shí)代的產(chǎn)品相比,它也是墊底的(見圖一)。同時(shí)代的BoneCP更是直接以干掉它為自己的口號(官網(wǎng)號稱比c3p0快25倍),更不要說和后來的druid和HikariCP相比了。

正常來講,有問題很正常,改就是了,但c3p0最致命的問題就是架構(gòu)設(shè)計(jì)過于復(fù)雜,讓重構(gòu)變成了一項(xiàng)不可能完成的任務(wù)。隨著國內(nèi)互聯(lián)網(wǎng)大潮的涌起,性能有硬傷的c3p0徹底的退出了歷史舞臺。

如果說c3p0被人嫌棄,是因?yàn)樗陨砑軜?gòu)設(shè)計(jì)的“原罪”,那proxool的冷門,則是與作者興趣的缺失有關(guān)。proxool最初在設(shè)計(jì)上另辟蹊徑,以JDBC驅(qū)動的身份為用戶提供連接池服務(wù),這使得將proxool移植到現(xiàn)有代碼中別的十分容易,而且proxool還開創(chuàng)性的提供了連接池監(jiān)控功能,讓它迅速的獲得了不少用戶的青睞。

但產(chǎn)品作者興趣的缺失,讓這款本來很有潛力的產(chǎn)品早早夭折。在github的項(xiàng)目首頁,作者寫到:“我從2006年之后就再沒碰過這個(gè)項(xiàng)目了,我甚至練Java都不用了...”,也許,proxool本來就是這位天才coder的練手之作,java本身也不是他的主力語言,但不論哪種原因,proxool都已經(jīng)和c3p0一樣,鮮有人問津了。

This project is no longer actively maintained. I haven't used Proxool myself since 2006 and no longer even use Java. If the project has any chance of survival at all it would need to find a new maintainer. If anyone can recommend a good alternative I would be happy to mention it here. Alternatively, if anyone wants to contribute to this project then please create a pull request.

圖一:第一代連接池性能測試

咸魚翻身的dbcp

dbcp(DataBase Connection Pool)屬于Apache頂級項(xiàng)目Commons中的核心子項(xiàng)目(最早在Jakarta Commons里就有),在Apache的生態(tài)圈中的影響里十分廣泛,比如最為大家所熟知的tomcat就在內(nèi)部集成了dbcp,實(shí)現(xiàn)JPA規(guī)范的OpenJPA,也是默認(rèn)集成dbcp的。但dbcp并不是獨(dú)立實(shí)現(xiàn)連接池功能的,它內(nèi)部依賴于Commons中的另一個(gè)子項(xiàng)目pool,連接池最核心的“池”,就是由pool組件提供的,因此,dbcp的性能實(shí)際上就是pool的性能,dbcp和pool的依賴關(guān)系如下表:

Apache Commons DBCP Apache Commons Pool
v1.2.2 v1.3
v1.3 v1.5.4
v1.4 v1.5.4
v2.0.x v2.2
v2.1.x v2.4.2

可以看到,因?yàn)楹诵墓δ芤蕾囉趐ool,所以dbcp本身只能做小版本的更新,真正大版本的更迭則完全依托于pool。有很長一段時(shí)間,pool都還是停留在1.x版本,這直接導(dǎo)致dbcp也更新乏力。很多依賴dbcp的應(yīng)用在遇到性能瓶頸之后,別無選擇,只能將其替換掉,dbcp忠實(shí)的擁躉tomcat就在其tomcat 7.0版本中,自己重新設(shè)計(jì)開發(fā)出了一套連接池(Tomcat JDBC Pool)。好在,在2013年事情終于迎來轉(zhuǎn)機(jī),13年9月Commons-Pool 2.0版本發(fā)布,14年2月份,dbcp也終于迎來了自己的2.0版本,基于新的線程模型全新設(shè)計(jì)的“池”讓dbcp重?zé)ㄇ啻海m然和新一代的連接池相比仍有一定差距,但差距并不大,dbcp 2.x版本已經(jīng)穩(wěn)穩(wěn)達(dá)到了和新一代產(chǎn)品同級別的性能指標(biāo)(見下圖)。

圖二:DBCP 2.x與新一代產(chǎn)品的性能對比

dbcp終于靠pool咸魚翻身,打了一個(gè)漂亮的翻身仗,但長時(shí)間的等待已經(jīng)完全消磨了用戶的耐心,與新一代的產(chǎn)品項(xiàng)目相比,dbcp沒有任何優(yōu)勢,試問,誰會在有選擇的前提下,去選擇那個(gè)并不優(yōu)秀的呢?也許,現(xiàn)在還選擇dbcp2的唯一理由,就是情懷吧。

甘心赴死的BoneCP

在討論BoneCP這塊的內(nèi)容之前,我們還是先來看看BoneCP作者自己是這么評價(jià)這款產(chǎn)品的:

BoneCP is a Java JDBC connection pool implementation that is tuned for high performance by minimizing lock contention to give greater throughput for your applications. It beats older connection pools such as C3P0 and DBCP but should now be considered deprecated in favour of HikariCP.

用我自己的話翻譯一下就是:俺是一個(gè)高性能的數(shù)據(jù)庫連接池,俺之所以這么牛逼是因?yàn)榘吃趯?shí)現(xiàn)的時(shí)候減少了鎖的使用,想當(dāng)年,什么c3p0啊DBCP啊都被老子干趴了,但是現(xiàn)在為了支持HikariCP,俺選擇退出!也就是說,BoneCP的退出是它自己的選擇,但它又不像proxool是被拋棄的,它是作者經(jīng)過深思熟慮后,做出的選擇,可以說BoneCP是“甘心赴死,殺身成仁”。那么問題來了,BoneCP究竟是不是像它自己形容的那樣牛逼?BoneCP和HikariCP之間究竟有啥聯(lián)系,能引得它主動“金盆洗手”?

先說性能,BoneCP自稱性能是c3p0的25倍,并提供了依照自己定義的測試案例,提供了一組圖片

  1. 單線程(1,000,000獲得及釋放數(shù)據(jù)庫連接請求,連接池大小20-50)


    單線程
  2. 多線程(500線程分別獲取釋放100個(gè)鏈接,連接池大小50-200)


    多線程1
  3. 多線程(500個(gè)線程每個(gè)100次獲得/釋放,連接池大小20-500)


    多線程2

當(dāng)然,以上圖片僅供參考,因?yàn)椴煌膮?shù)配置,不同的應(yīng)用環(huán)境,不同的測試案例,得到的結(jié)果肯定也不會相同,官網(wǎng)提供的數(shù)據(jù),肯定是在最有利于自己表現(xiàn)的環(huán)境下得到的。但結(jié)合另外一份測試數(shù)據(jù)(第一幅圖),可以看到BoneCP的性能在第一代產(chǎn)品中,確實(shí)是屬于領(lǐng)先地位的。高性能的表現(xiàn)的秘訣也并不高深,一是極簡的設(shè)計(jì),整個(gè)產(chǎn)品只有幾百k大小,二是重構(gòu)內(nèi)部pool的設(shè)計(jì),減少鎖的使用,而這兩點(diǎn)優(yōu)化原則,幾乎適用于所以的連接池產(chǎn)品。

值得一提的是,BoneCP本身并不“健全”,它的很多特征都依賴于Guava,因此也就和dbcp一樣,面臨更新乏力的問題。但現(xiàn)在,這些問題都不重要了,因?yàn)樗囈詾榘恋男阅鼙籋ikariCP全面超越。HikariCP可以說是BoneCP的二代產(chǎn)品(HikariCP自己在官網(wǎng)上聲稱在BoneCP的基礎(chǔ)上,做了很多優(yōu)化),它在設(shè)計(jì)思路上和BoneCP完全一致,主打的特征也是超強(qiáng)的性能表現(xiàn),關(guān)于HikariCP的詳細(xì)內(nèi)容,我將在下一章節(jié)介紹。

站在巨人肩膀上的第二代連接池

在數(shù)據(jù)庫連接池的產(chǎn)品群中,二代產(chǎn)品對一代產(chǎn)品的超越是顛覆性的,除了一些“歷史原因”,你很難再找到第二條理由說服自己不選擇二代產(chǎn)品,但任何成功都不是偶然的,二代產(chǎn)品的成功很大程度上得益于前代產(chǎn)品們打下的基礎(chǔ),站在巨人的肩膀上,新一代的連接池的設(shè)計(jì)師們將這一項(xiàng)“工具化”的產(chǎn)品,推向了極致。其中,最具代表性的兩款產(chǎn)品是:

  • HikariCP
  • druid

性能無敵的HikariCP

剛剛在介紹BoneCP的時(shí)候多少已經(jīng)提到過HikariCP了,作為連接池產(chǎn)品中的“性能殺手”,它的表現(xiàn)究竟如何呢,先來看下官網(wǎng)提供的數(shù)據(jù):


圖三:HikariCP官網(wǎng)配圖1
圖三:HikariCP官網(wǎng)配圖1

不光性能強(qiáng)勁,穩(wěn)定性也不差:


圖四:HikariCP官方配圖2

那它是怎么做到如此強(qiáng)勁的呢?官網(wǎng)給出的說明如下:

  • 字節(jié)碼精簡:優(yōu)化代碼,直到編譯后的字節(jié)碼最少,這樣,CPU緩存可以加載更多的程序代碼;
  • 優(yōu)化代理和攔截器:減少代碼,例如HikariCP的Statement proxy只有100行代碼,只有BoneCP的十分之一;
  • 自定義數(shù)組類型(FastStatementList)代替ArrayList:避免每次get()調(diào)用都要進(jìn)行range check,避免調(diào)用remove()時(shí)的從頭到尾的掃描;
  • 自定義集合類型(ConcurrentBag):提高并發(fā)讀寫的效率;
  • 其他針對BoneCP缺陷的優(yōu)化,比如對于耗時(shí)超過一個(gè)CPU時(shí)間片的方法調(diào)用的研究(但沒說具體怎么優(yōu)化)。

可以看到,上述這幾點(diǎn)優(yōu)化,針對的都是BoneCP現(xiàn)有的缺陷,優(yōu)化到這份上,也難怪BoneCP的作者不想玩了。綜合現(xiàn)在能找到的資料來看,HakariCP在性能上的優(yōu)勢應(yīng)該是得到共識的,再加上它自身小巧的身形,在當(dāng)前的“云時(shí)代、微服務(wù)”的背景下,HakariCP一定會得到更多人的青睞。

功能全面的druid

近幾年,阿里在開源項(xiàng)目上動作頻頻,除了有像fastJson這類工具型項(xiàng)目,更有像AliSQL這類的大型軟件,今天說的druid,就是阿里眾多優(yōu)秀開源項(xiàng)目中的一個(gè)。它除了提供性能卓越的連接池功能外,還集成了sql監(jiān)控,黑名單攔截等功能,用它自己的話說,druid是“為監(jiān)控而生”。借助于阿里這個(gè)平臺的號召力,產(chǎn)品一經(jīng)發(fā)布就贏得了大批用戶的擁躉,從用戶使用的反饋來看,druid也確實(shí)沒讓用戶失望。

相較于其他產(chǎn)品,druid另一個(gè)比較大的優(yōu)勢,就是中文文檔比較全面(畢竟是國人的項(xiàng)目么),在github的wiki頁面,列舉了日常使用中可能遇到的問題,對一個(gè)新用戶來講,上面提供的內(nèi)容已經(jīng)足夠指導(dǎo)它完成產(chǎn)品的配置和使用了。

下圖為druid自己提供的性能測試數(shù)據(jù):


圖五:druid提供的性能測試數(shù)據(jù)

最后,隱身的連接池

時(shí)至今日,雖然每個(gè)應(yīng)用(需要RDBMS的)都離不開連接池,但在實(shí)際使用的時(shí)候,連接池已經(jīng)可以做到“隱形”了。也就是說在通常情況下,連接池完成項(xiàng)目初始化配置之后,就再不需要再做任何改動了。不論你是選擇druid或是HikariCP,甚至是DBCP,它們都足夠穩(wěn)定且高效!我們之前討論了很多關(guān)于連接池的性能的問題,但這些性能上的差異,是相交于其他連接池而言的,對整個(gè)系統(tǒng)應(yīng)用來說,第二代連接池在使用過程中體會到的差別是微乎其微的,基本上不存在因?yàn)檫B接池的自身的配飾和使用導(dǎo)致系統(tǒng)性能下降的情況,除非是在單點(diǎn)應(yīng)用的數(shù)據(jù)庫負(fù)載足夠高的時(shí)候(壓力測試的時(shí)候),但即便是如此,通用的優(yōu)化的方式也是單點(diǎn)改集群,而不是在單點(diǎn)的連接池上死扣。

與我而言,連接池是我打開自己技術(shù)棧(Java存儲層相關(guān))的起點(diǎn),它有著作為起點(diǎn)的一切優(yōu)點(diǎn):使用廣泛,入門簡單,同時(shí)核心思想和實(shí)踐又足夠有料。本篇文章僅是一個(gè)開端,既是幫助我(和大家)理清楚市面上這些產(chǎn)品的現(xiàn)狀,同時(shí)也為為接下來馬上開始的“深入研究”鋪點(diǎn)底子。如果一定要說點(diǎn)什么感悟的話,那我只能再一次感嘆開源的力量以及社區(qū)對Java技術(shù)推廣的巨大助力。開源是一種精神,分享是一種態(tài)度,而這,正是Java語言幾十年依舊屹立不倒的原因。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,536評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內(nèi)容