摘要:你僅僅需要一個大小為數(shù)據(jù)庫連接池,然后讓剩下的業(yè)務(wù)線程都在隊列里等待就可以了。你應(yīng)該經(jīng)常會看到一些用戶量不是很大的應(yīng)用中,為應(yīng)付大約十來個的并發(fā),卻將數(shù)據(jù)庫連接池設(shè)置成,的情況。請不要過度配置您的數(shù)據(jù)庫連接池的大小。
文章翻譯整理自: https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing目錄歡迎關(guān)注個人微信公眾號: 小哈學(xué)Java, 文末分享阿里 P8 高級架構(gòu)師吐血總結(jié)的 《Java 核心知識整理&面試.pdf》資源鏈接??!
個人網(wǎng)站: https://www.exception.site/essay/how-to-set-the-size-of-database-connection-pool
一、筆者前言
二、正菜開始
三、假設(shè)你的服務(wù)有1萬并發(fā)的訪問
四、為啥有這種效果?
五、其他應(yīng)該考慮到的因素
六、連接數(shù)計算公式
七、結(jié)論:你需要的是一個小連接池,和一個等待連接的線程隊列
八、額外需要注意的點
一、筆者前言基本上來說,大部分項目都需要跟數(shù)據(jù)庫做交互,那么,數(shù)據(jù)庫連接池的大小設(shè)置成多大合適呢?
一些開發(fā)老鳥可能還會告訴你:沒關(guān)系,盡量設(shè)置的大些,比如設(shè)置成 200,這樣數(shù)據(jù)庫性能會高些,吞吐量也會大些!
你也許會點頭稱是,真的是這樣嗎?看完這篇文章,也許會顛覆你的認(rèn)知哦!
二、正菜開始可以很直接的說,關(guān)于數(shù)據(jù)庫連接池大小的設(shè)置,每個開發(fā)者都可能在一環(huán)節(jié)掉進(jìn)坑里,事實上呢,大部分程序員可能都會依靠自己的直覺去設(shè)置它的大小,設(shè)置成 100 ?思量許久后,自顧自想,應(yīng)該差不多吧?
三、假設(shè)你的服務(wù)有1萬并發(fā)的訪問不妨意淫一下,你手里有個網(wǎng)站,并發(fā)壓力雖然還沒到 Facebook 那個級別,但是呢?也有個1萬上下的并發(fā)量!也就是說差不多2萬左右的 TPS。
那么問題來了!這個網(wǎng)站的數(shù)據(jù)庫連接池應(yīng)該設(shè)置成多大合適呢?
其實這個問法本身就是有問題的,我們需要反過來問,正確問法應(yīng)該是:
“這個網(wǎng)站的數(shù)據(jù)庫連接池應(yīng)該設(shè)置成多小合適呢?”
PS: 這里有一個 Oracle 性能小組發(fā)布的簡短視頻,鏈接地址為 http://www.dailymotion.com/video/x2s8uec
口述一下,視頻中對 Oracle 數(shù)據(jù)庫進(jìn)行了壓力測試,模擬 9600 個并發(fā)線程來操作數(shù)據(jù)庫,每兩次數(shù)據(jù)庫操作之間 sleep 550ms,注意,視頻中剛開始設(shè)置的線程池大小為 2048。
讓我們來看看數(shù)據(jù)庫連接池的大小為 2048 性能測試結(jié)果的鬼樣子:
每個請求要在連接池隊列里等待 33ms,獲得連接之后,執(zhí)行SQL需要耗時77ms, CPU 消耗維持在 95% 左右;
接下來,我們將連接池的大小改小點,設(shè)置成 1024,其他測試參數(shù)不變,結(jié)果咋樣?
"這里,獲取連接等待時長基本不變,但是 SQL 的執(zhí)行耗時降低了!"
哎呦,有長進(jìn)哦!
接下來,我們再設(shè)置小些,連接池的大小降低到 96,并發(fā)數(shù)等其他參數(shù)不變,看看結(jié)果如何:
每個請求在連接池隊列中的平均等待時間為 1ms, SQL 執(zhí)行耗時為 2ms.
我去!什么鬼?
我們沒調(diào)整任何東西,僅僅只是將數(shù)據(jù)庫連接池的大小降低了,這樣,就能把之前平均 100ms 響應(yīng)時間縮短到了 3ms。吞吐量指數(shù)級上升??!
你這也太溜了!
四、為啥有這種效果?我們不妨想一下,為啥 Nginx 內(nèi)部僅僅使用了 4 個線程,其性能就大大超越了 100 個進(jìn)程的 Apache HTTPD 呢?追究其原因的話,回想一下計算機(jī)科學(xué)的基礎(chǔ)知識,答案其實非常明顯。
要知道,即使是單核 CPU 的計算機(jī)也能“同時”運行著數(shù)百個線程。但我們其實都知道,這只不過是操作系統(tǒng)快速切換時間片,跟我們玩的一個小把戲罷了。
一核 CPU同一時刻只能執(zhí)行一個線程,然后操作系統(tǒng)切換上下文,CPU 核心快速調(diào)度,執(zhí)行另一個線程的代碼,不停反復(fù),給我們造成了所有進(jìn)程同時運行假象。
其實,在一核 CPU 的機(jī)器上,順序執(zhí)行A和B永遠(yuǎn)比通過時間分片切換“同時”執(zhí)行A和B要快,其中原因,學(xué)過操作系統(tǒng)這門課程的童鞋應(yīng)該很清楚。一旦線程的數(shù)量超過了 CPU 核心的數(shù)量,再增加線程數(shù)系統(tǒng)就只會更慢,而不是更快,因為這里涉及到上下文切換耗費的額外的性能。
說到這里,你應(yīng)該恍然大悟了 ……
五、其他應(yīng)該考慮到的因素上小節(jié)中說到了主要原因,但其實沒有這么簡單,我們還需要考慮到一些其他的因素。
當(dāng)我們在尋找數(shù)據(jù)庫的性能瓶頸時,大致可歸為三類:
CPU
磁盤 IO
網(wǎng)絡(luò) IO
也許你會說,還有內(nèi)存這一因素?內(nèi)存的確是需要考慮的,但是比起磁盤IO和網(wǎng)絡(luò)IO,稍顯微不足道,這里就不加了。
假設(shè)我們不考慮磁盤 IO 和網(wǎng)絡(luò) IO,就很好定論了,在一個 8 核的服務(wù)器上,數(shù)據(jù)庫連接數(shù)/線程數(shù)設(shè)置為 8 能夠提供最優(yōu)的性能,如果再增加連接數(shù),反而會因為上下文切換導(dǎo)致性能下降。
大家都知道,數(shù)據(jù)庫通常把數(shù)據(jù)存儲在磁盤上,而磁盤呢,通常是由一些旋轉(zhuǎn)著的金屬碟片和一個裝在步進(jìn)馬達(dá)上的讀寫頭組成的。讀/寫頭同一時刻只能出現(xiàn)在一個位置,當(dāng)它需要再次執(zhí)行讀寫操作時,它必須“尋址”到另外一個位置才能完成任務(wù)。所以呢?這里就有了尋址的耗時,此外還有旋轉(zhuǎn)耗時,讀寫頭需要等待磁盤碟片上的目標(biāo)數(shù)據(jù)“旋轉(zhuǎn)到位”才能進(jìn)行讀寫操作。使用緩存當(dāng)然是能夠提升性能的,但上述原理仍然適用。
在這段("I/O等待")時間內(nèi),線程是處于“阻塞”等待狀態(tài),也就是說沒干啥正事!此時操作系統(tǒng)可以將這個空閑的CPU 核心用于服務(wù)其他線程。
這里我們可以總結(jié)一下,當(dāng)你的線程處理的是 I/O 密集型業(yè)務(wù)時,便可以讓線程/連接數(shù)設(shè)置的比 CPU核心大一些,這樣就能夠在同樣的時間內(nèi),完成更多的工作,提升吞吐量。
那么問題又來了?
大小設(shè)置成多少合適呢?
這要取決于磁盤,如果你使用的是 SSD 固態(tài)硬盤,它不需要尋址,也不需要旋轉(zhuǎn)碟片。打住打住?。。∧闱f可別理所當(dāng)然的認(rèn)為:“既然SSD速度更快,我們把線程數(shù)的大小設(shè)置的大些吧?。?/strong>”
結(jié)論正好相反!無需尋址和沒有旋回耗時的確意味著更少的阻塞,所以更少的線程(更接近于CPU核心數(shù))會發(fā)揮出更高的性能。只有當(dāng)阻塞密集時,更多的線程數(shù)才能發(fā)揮出更好的性能。
上面我們已經(jīng)說過了磁盤 IO, 接下來我們談?wù)劸W(wǎng)絡(luò) IO!
網(wǎng)絡(luò) IO 其實也是非常相似的。通過以太網(wǎng)接口讀寫數(shù)據(jù)時也會造成阻塞,10G帶寬會比1G帶寬的阻塞耗時少一些,而 1G 帶寬又會比 100M 帶寬的阻塞少一些。通常情況下,我們把網(wǎng)絡(luò) IO 放在第三順位來考慮,然而有些人會在性能計算中忽略網(wǎng)絡(luò) IO 帶來的影響。
上圖是 PostgreSQL 的基準(zhǔn)性能測試數(shù)據(jù),從圖中我們可以看到,TPS 在連接數(shù)達(dá)到 50 時開始變緩?;剡^頭來想下,在上面 Oracle 的性能測試視頻中,測試人員們將連接數(shù)從 2048 降到了 96,實際上 96 還是太高了,除非你的服務(wù)器 CPU 核心數(shù)有 16 或 32。
六、連接數(shù)計算公式下面公式由 PostgreSQL 提供,不過底層原理是不變的,它適用于市面上絕大部分?jǐn)?shù)據(jù)庫產(chǎn)品。還有,你應(yīng)該模擬預(yù)期的訪問量,并通過下面的公式先設(shè)置一個偏合理的值,然后在實際的測試中,通過微調(diào),來尋找最合適的連接數(shù)大小。
連接數(shù) = ((核心數(shù) * 2) + 有效磁盤數(shù))
核心數(shù)不應(yīng)包含超線程(hyper thread),即使打開了超線程也是如此,如果熱點數(shù)據(jù)全被緩存了,那么有效磁盤數(shù)實際是0,隨著緩存命中率的下降,有效磁盤數(shù)也逐漸趨近于實際的磁盤數(shù)。另外需要注意,這一公式作用于SSD 的效果如何,尚未明了。
好了,按照這個公式,如果說你的服務(wù)器 CPU 是 4核 i7 的,連接池大小應(yīng)該為 ((4 * 2) + 1) = 9。
取個整, 我們就設(shè)置為 10 吧。你這個行不行啊?10 也太小了吧!
你要是覺得不太行的話,可以跑個性能測試看看,我們可以保證,它能輕松支撐 3000 用戶以 6000 TPS 的速率并發(fā)執(zhí)行簡單查詢的場景。你還可以將連接池大小超過 10,那時,你會看到響應(yīng)時長開始增加,TPS 開始下降。
七、結(jié)論:你需要的是一個小連接池,和一個等待連接的線程隊列假設(shè)說你有 10000 個并發(fā)訪問,而你設(shè)置了連接池大小為 10000,你怕是石樂志哦。
改成 1000,太高?改成 100?還是太多了。
你僅僅需要一個大小為 10 數(shù)據(jù)庫連接池,然后讓剩下的業(yè)務(wù)線程都在隊列里等待就可以了。
連接池中的連接數(shù)量大小應(yīng)該設(shè)置成:數(shù)據(jù)庫能夠有效同時進(jìn)行的查詢?nèi)蝿?wù)數(shù)(通常情況下來說不會高于 2*CPU核心數(shù))。
你應(yīng)該經(jīng)常會看到一些用戶量不是很大的 web 應(yīng)用中,為應(yīng)付大約十來個的并發(fā),卻將數(shù)據(jù)庫連接池設(shè)置成 100, 200 的情況。請不要過度配置您的數(shù)據(jù)庫連接池的大小。
八、額外需要注意的點實際上,連接池的大小的設(shè)置還是要結(jié)合實際的業(yè)務(wù)場景來說事。
比如說,你的系統(tǒng)同時混合了長事務(wù)和短事務(wù),這時,根據(jù)上面的公式來計算就很難辦了。正確的做法應(yīng)該是創(chuàng)建兩個連接池,一個服務(wù)于長事務(wù),一個服務(wù)于"實時"查詢,也就是短事務(wù)。
還有一種情況,比方說一個系統(tǒng)執(zhí)行一個任務(wù)隊列,業(yè)務(wù)上要求同一時間內(nèi)只允許執(zhí)行一定數(shù)量的任務(wù),這時,我們就應(yīng)該讓并發(fā)任務(wù)數(shù)去適配連接池連接數(shù),而不是連接數(shù)大小去適配并發(fā)任務(wù)數(shù)。
Refhttps://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
免費分享 | 面試&學(xué)習(xí)福利資源最近在網(wǎng)上發(fā)現(xiàn)一個不錯的 PDF 資源《Java 核心知識&面試.pdf》分享給大家,不光是面試,學(xué)習(xí),你都值得擁有?。?!
獲取方式: 關(guān)注公眾號: 小哈學(xué)Java, 后臺回復(fù)資源,既可免費無套路獲取資源鏈接,下面是目錄以及部分截圖:
重要的事情說兩遍,關(guān)注公眾號: 小哈學(xué)Java, 后臺回復(fù)資源,既可免費無套路獲取資源鏈接 ?。?!
歡迎關(guān)注微信公眾號: 小哈學(xué)Java文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/77690.html
摘要:你僅僅需要一個大小為數(shù)據(jù)庫連接池,然后讓剩下的業(yè)務(wù)線程都在隊列里等待就可以了。你應(yīng)該經(jīng)常會看到一些用戶量不是很大的應(yīng)用中,為應(yīng)付大約十來個的并發(fā),卻將數(shù)據(jù)庫連接池設(shè)置成,的情況。請不要過度配置您的數(shù)據(jù)庫連接池的大小。 文章翻譯整理自: https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing歡迎關(guān)注個人微信公眾...
摘要:例如資源的獲取,支持多種消息例如的支持,對多了工具級別的支持等待。最上面的知道吧我就不講了。生命周期事件回調(diào)等。他支持不同信息源頭,支持工具類,支持層級容器,支持訪問文件資源,支持事件發(fā)布通知,支持接口回調(diào)等等。 廣義的 IOC IoC(Inversion of Control) 控制反轉(zhuǎn),即不用打電話過來,我們會打給你。 兩種實現(xiàn): 依賴查找(DL)和依賴注入(DI)。 IOC 和...
閱讀 2507·2021-11-25 09:43
閱讀 1272·2021-09-07 10:16
閱讀 2693·2021-08-20 09:38
閱讀 2998·2019-08-30 15:55
閱讀 1553·2019-08-30 13:21
閱讀 971·2019-08-29 15:37
閱讀 1499·2019-08-27 10:56
閱讀 2138·2019-08-26 13:45