大話數(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

我對(duì)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)對(duì)它的穩(wěn)定行還是認(rèn)可的。關(guān)于c3p0如何使用蘸际,可以借助于搜索引擎座哩,這里就不再贅述了。c3p0功能簡單易用粮彤,穩(wěn)定性好這是它的優(yōu)點(diǎn)根穷,但性能上的缺點(diǎn)卻讓它徹底被打入冷宮。c3p0的性能很差导坟,差到即便是和同時(shí)代的產(chǎn)品相比屿良,它也是墊底的(見圖一)。同時(shí)代的BoneCP更是直接以干掉它為自己的口號(hào)(官網(wǎng)號(hào)稱比c3p0快25倍)惫周,更不要說和后來的druid和HikariCP相比了尘惧。

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

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

但產(chǎn)品作者興趣的缺失匾二,讓這款本來很有潛力的產(chǎn)品早早夭折。在github的項(xiàng)目首頁,作者寫到:“我從2006年之后就再?zèng)]碰過這個(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.

圖一:第一代連接池性能測(cè)試

咸魚翻身的dbcp

dbcp(DataBase Connection Pool)屬于Apache頂級(jí)項(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)品同級(jí)別的性能指標(biāo)(見下圖)。

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

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

甘心赴死的BoneCP

在討論BoneCP這塊的內(nèi)容之前,我們還是先來看看BoneCP作者自己是這么評(píng)價(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)系嫂伞,能引得它主動(dòng)“金盆洗手”孔厉?

先說性能,BoneCP自稱性能是c3p0的25倍帖努,并提供了依照自己定義的測(cè)試案例撰豺,提供了一組圖片

  1. 單線程(1,000,000獲得及釋放數(shù)據(jù)庫連接請(qǐng)求,連接池大小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)境,不同的測(cè)試案例舅柜,得到的結(jié)果肯定也不會(huì)相同梭纹,官網(wǎng)提供的數(shù)據(jù),肯定是在最有利于自己表現(xiàn)的環(huán)境下得到的致份。但結(jié)合另外一份測(cè)試數(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)品對(duì)一代產(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ā)讀寫的效率龙考;
  • 其他針對(duì)BoneCP缺陷的優(yōu)化蟆肆,比如對(duì)于耗時(shí)超過一個(gè)CPU時(shí)間片的方法調(diào)用的研究(但沒說具體怎么優(yōu)化)。

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

功能全面的druid

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

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

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


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

最后薄料,隱身的連接池

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

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

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市揍庄,隨后出現(xiàn)的幾起案子咆蒿,更是在濱河造成了極大的恐慌,老刑警劉巖蚂子,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沃测,死亡現(xiàn)場離奇詭異,居然都是意外死亡食茎,警方通過查閱死者的電腦和手機(jī)蒂破,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來董瞻,“玉大人寞蚌,你說我怎么就攤上這事∧坪” “怎么了挟秤?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長抄伍。 經(jīng)常有香客問我艘刚,道長,這世上最難降的妖魔是什么截珍? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任攀甚,我火速辦了婚禮,結(jié)果婚禮上岗喉,老公的妹妹穿的比我還像新娘秋度。我一直安慰自己,他們只是感情好钱床,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布荚斯。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪事期。 梳的紋絲不亂的頭發(fā)上滥壕,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天,我揣著相機(jī)與錄音兽泣,去河邊找鬼绎橘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛唠倦,可吹牛的內(nèi)容都是我干的称鳞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼稠鼻,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼胡岔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起枷餐,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苫亦,沒想到半個(gè)月后毛肋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屋剑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年润匙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唉匾。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孕讳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巍膘,到底是詐尸還是另有隱情厂财,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布峡懈,位于F島的核電站璃饱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肪康。R本人自食惡果不足惜荚恶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望磷支。 院中可真熱鬧谒撼,春花似錦、人聲如沸雾狈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至茉帅,卻和暖如春叨叙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堪澎。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來泰國打工擂错, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人樱蛤。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓钮呀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昨凡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子爽醋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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