填充一个池需要多少个线程?
近幾個月來,我們一直看到一小部分但持續的操作失敗,并帶有一個奇怪的異常– org.springframework.jdbc.CannotGetJdbcConnectionException –“無法獲得JDBC連接; 嵌套異常是java.sql.SQLException:客戶端嘗試檢出Connection的嘗試已超時。 ”
我們自然的假設是,我們的C3P0連接池存在某種爭用,試圖獲取連接的客戶端必須等待該爭用可用。 我們最好的猜測是正是這種爭用導致了超時。
因此,當然,我們要做的第一件事是增加連接池中的最大連接數。 但是,無論我們將限制設置得多么高,它都無濟于事。 然后,我們嘗試更改連接的超時參數。 那沒有產生任何更好的結果。
此時,情報已經確定下來,并且由于猜測似乎沒有用,因此我們決定進行測量。 在連接池上使用一個簡單的包裝程序,我們看到即使連接池中有空閑連接,我們仍然會得到簽出超時。
調查連接池開銷
為了研究連接池開銷,我們執行了一個基準測試,該基準測試由6個回合組成,每個回合包括20,000個SQL操作(讀/寫比為1:10),使用20個線程和20個連接的連接池來執行。 使用具有20個連接的池使用20個線程意味著資源(連接)上沒有爭用。 因此,任何開銷都是由連接池本身引起的。
我們忽略了第一次(預熱)運行的結果,而取了隨后5次運行的統計數據。 從這些數據中,我們收集連接簽出時間,連接釋放時間和總池開銷。
基準項目代碼可以在以下位置找到: https : //github.com/yoavaa/connection-pool-benchmark
我們測試了3個不同的連接池:
- C3P0 – com.mchange:c3p0:0.9.5-pre3 – C3P0DataSourceBenchmark類
- Bone CP – com.jolbox:bonecp:0.8.0-rc1 –類BoneDataSourceBenchmark
- Apache DBCP – commons-dbcp:commons-dbcp:1.4 –類DbcpDataSourceBenchmark
(在該項目中,還有一個我自己的實驗性異步池的基準測試-https: //github.com/yoavaa/async-connection-pool 。但是,出于本文的目的,我將忽略它)。
為了自己運行基準測試,您應該使用下表設置MySQL
CREATE TABLE item (file_name?? ? varchar(100) NOT NULL,user_guid?? ? varchar(50) NOT NULL,media_type ?? varchar(16) NOT NULL,date_created? datetime NOT NULL,date_updated? timestamp AUTO_INCREMENT NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY(file_name) )然后更新Credentials對象以指向此MySQL安裝。
運行基準測試時,示例結果如下所示:
run, param, total time, errors, under 1000 nSec,1000 nSec - 3200 nSec,3200 nSec - 10 μSec,10 μSec - 32 μSec,32 μSec - 100 μSec,100 μSec - 320 μSec,320 μSec - 1000 μSec,1000 μSec - 3200 μSec,3200 μSec - 10 mSec,10 mSec - 32 mSec,32 mSec - 100 mSec,100 mSec - 320 mSec,320 mSec - 1000 mSec,1000 mSec - 3200 mSec,other 0, acquire,29587,0,0,5,1625,8132,738,660,1332,1787,2062,2048,1430,181,0,0,0 0, execution, , ,0,0,0,0,0,0,0,1848,6566,6456,5078,52,0,0,0 0, release, , ,0,8,6416,9848,3110,68,77,115,124,148,75,11,0,0,0 0, overhead, , ,0,0,49,4573,5459,711,1399,1812,2142,2157,1498,200,0,0,0 1, acquire,27941,0,0,125,8153,499,658,829,1588,2255,2470,2377,1013,33,0,0,0 1, execution, , ,0,0,0,0,0,0,6,1730,6105,6768,5368,23,0,0,0 1, release, , ,0,49,15722,3733,55,42,69,91,123,101,14,1,0,0,0 1, overhead, , ,0,0,2497,5819,869,830,1610,2303,2545,2448,1042,37,0,0,0此信息已導入Excel文件(也包含在基準項目中)以進行分析。
C3P0
最初在C3P0中,我們在生產環境中看到了原始異常。 讓我們看看它如何執行:
閱讀圖表:
前三個圖表(獲取,發布,開銷)是基于性能的存儲桶圖表。 Y軸表示在一定時間范圍內完成的操作數(在X軸上顯示)。 默認的經驗法則是,左側的條形越高,效果越好。 第4 個圖表是瀑布圖,其中每個水平線表示一個DB操作。 棕色表示等待獲取連接的時間,綠色表示執行數據庫操作的時間,藍色表示將連接返回到連接池的時間。
從圖表中可以看出,通常,C3P0在3.2-10微秒內獲得連接,并在3.2-10微秒內釋放連接。 那絕對是一些令人印象深刻的表現。 但是,C3P0在約3.2-32毫秒處還有另一個峰值,而長尾巴則高達320-1000毫秒。 正是第二個高峰導致了我們的例外。
C3P0怎么了? 是什么原因導致了這種極小但相當大的超長操作百分比,而大多數時候卻表現驚人? 縱觀4 個圖可以為我們指出了答案的方向。
第4 個圖表從左上角到右下角有一條清晰的對角線,表明總體上,連接獲取是按順序開始的。 但是我們可以識別出一些奇怪的東西–我們可以看到棕色的三角形,表示當多個線程試圖獲取連接時,第一個線程比隨后的線程等待更多的時間。 這轉化為用于獲取連接的兩個性能“組”。 一些線程極其快速地獲得連接,而有些線程則餓死等待連接,而較后的線程的請求則得到了較早的答復。
早期線程比后續線程等待更長的時間的這種行為意味著不公平的同步。 事實上,挖掘到C3P0代碼時,我們已經看到了收購的連接的過程中,C3P0使用“ 同步 ”關鍵字三次。 在Java中,“ synced ”關鍵字創建了不公平的鎖定,這可能導致線程饑餓。
稍后我們可能會嘗試使用公平鎖定來修補C3P0。 如果這樣做,我們自然會分享我們的發現。
此基準測試的C3P0配置:
- 最小泳池大小:20
- 初始池大小:20
- 泳池最大大小:20
- 采集增量:10
- 輔助線程數:6
骨CP
我們在Wix上嘗試了BoneCP,但結果卻不盡相同,因此目前尚不確定我們是否喜歡它。 盡管分析并不全面,但我們將BoneCP基準測試的結果包括在這些帖子中。
查看圖表,我們可以看到Bone的連接捕獲性能非常出色–大多數操作在3.2微秒內完成,比C3P0快得多。 但是,我們還觀察到連接釋放時間很長,大約1-10毫秒,太高了。 我們還觀察到Bone的操作很長,開銷高達320毫秒。
從數據來看,在正常情況和“極端”情況下,BoneCP似乎都比C3P0好。 但是,如圖表所示,差異并不大。 查看第4 個圖表,我們看到與C3P0相比,棕色更少(因為連接獲取更好),但出現了藍線,表明線程等待連接釋放的時間。
如上所述,由于我們對使用BoneCP充其量是矛盾的,因此我們沒有投入大量資源來分析此連接池的性能問題。
Apache DBCP
Apache DBCP被稱為古老的數據源。 讓我們來看看與其他兩個相比的情況。
顯而易見的是-DBCP性能優于C3P0和Bone。 在所有方面,無論是在連接檢查時間,連接釋放時間還是瀑布圖形式方面,它都優于其他方法。
那么您應該使用什么數據源?
好吧,這是一個不平凡的問題。 顯然,就連接池性能而言,我們顯然是贏家– DBCP。 似乎C3P0應該很容易修復,我們可以嘗試一下。
但是,請務必記住,此調查的范圍僅限于實際連接獲取/釋放的性能。 實際的數據源選擇是一個更復雜的問題。 例如,該基準測試忽略了一些重要方面,例如池的增長和縮小,網絡錯誤的處理,數據庫故障時的故障轉移等等。
翻譯自: https://www.javacodegeeks.com/2013/06/how-many-threads-does-it-take-to-fill-a-pool.html
總結
以上是生活随笔為你收集整理的填充一个池需要多少个线程?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何克隆路由器MAC地址两台路由器如何克
- 下一篇: 设置Apache Hadoop多节点集群