android wtf_WTF连接池
android wtf
讓我們談?wù)勥B接池。
我聲稱:
大多數(shù)流行的連接池的默認(rèn)設(shè)置都很差!
對您來說,這意味著:
去查看您的連接池設(shè)置。
如果您依賴默認(rèn)設(shè)置,則可能會(huì)遇到問題。 您可能有內(nèi)存泄漏和應(yīng)用程序無響應(yīng)(即使負(fù)載根本不高)。
下面,我將顯示一些最重要的設(shè)置以及我的建議,這些設(shè)置應(yīng)如何配置。
什么是連接池?
一個(gè)普通的Web應(yīng)用程序需要從數(shù)據(jù)庫寫入或讀取數(shù)據(jù),它是這樣的:
(順便說一下,在舊的良好CGI應(yīng)用程序中,這是唯一可能的方法)
在許多情況下,此方法非常好。 而且您可能不需要更多。 但這對于高性能系統(tǒng)有一些缺點(diǎn) :
- 步驟1可能需要一些時(shí)間。 大概幾十或幾百毫秒(當(dāng)然要取決于它)。
- 很容易忘記第3步(關(guān)閉連接),這會(huì)導(dǎo)致連接泄漏 (導(dǎo)致內(nèi)存泄漏和其他問題)。
新英雄
這就是誕生另一種方法的原因:應(yīng)用程序可能會(huì)預(yù)先打開一堆連接并一直保持打開狀態(tài)。 一堆打開的連接稱為連接池 。 然后任何操作如下所示:
看起來很酷。 但是,新的力量總是意味著新的問題。
…以及新問題
使用連接池時(shí),我們需要(至少)解決以下問題 :
- 我們應(yīng)該保持多少連接?
- 應(yīng)該保留多長時(shí)間?
- 如果它們看起來壞了怎么辦?
- 如果應(yīng)用程序需要的連接數(shù)超過當(dāng)前池的數(shù)量,該怎么辦?
- 如果有人忘記將連接恢復(fù)到池怎么辦?
為了回答這些問題,連接池有很多設(shè)置。 而且它們的默認(rèn)值大多不好。 感興趣嗎? 讓我展示。
基本設(shè)置
我將考慮Java世界中2個(gè)最流行的連接池:
- C3P0( https://www.mchange.com/projects/c3p0/ )
- HikariCP( https://github.com/brettwooldridge/HikariCP )
原因的基本參數(shù)是:
- 最小大小(隨時(shí)應(yīng)打開的最小連接數(shù))
- 初始大小(啟動(dòng)時(shí)打開了多少個(gè)連接應(yīng)用程序)
- 最大大小(池中的最大連接數(shù))
順便說一下,這些是唯一具有合理默認(rèn)值的設(shè)置。 他們來了:
| c3p0 | 光ikaCP | |
| 最小尺寸 | 3 | 10 |
| 初始尺寸 | 3 | 10 |
| 最大尺寸 | 15 | 10 |
讓我們繼續(xù)進(jìn)行更多有問題的設(shè)置。
關(guān)鍵設(shè)置
結(jié)帳超時(shí)
應(yīng)用程序可以等待多長時(shí)間,直到它從池中獲得連接。
- c3p0設(shè)置:checkoutTimeout
- HikariCP設(shè)置:connectionTimeout
默認(rèn)值:
| c3p0 | 光ikaCP | 我建議 | |
| checkoutTimeout | ∞ | 30秒 | 1毫秒 |
這兩個(gè)默認(rèn)值都只是災(zāi)難。
正如我提到的,在大多數(shù)情況下,從池中獲得連接非常快。 除非池中沒有打開的連接。 然后,池需要獲取一個(gè)新的連接(通常需要不到一秒鐘的時(shí)間)。 但是,如果達(dá)到maxSize,則池?zé)o法打開新的連接,而只是等到有人將其連接返回到池中。 但是,如果應(yīng)用程序發(fā)生連接泄漏(阻止連接返回的錯(cuò)誤),則池將永遠(yuǎn)無法恢復(fù)連接!
那會(huì)發(fā)生什么呢?
對于c3p0,我們最終將所有線程凍結(jié)為以下狀態(tài):
"qtp1905485420-495 13e09-3211" #495 prio=5 os_prio=0 tid=0x00007f20e078d800 nid=0x10d7 in Object.wait() [0x00007f204bc79000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable()- locked <0x00000000c3295ef8> (a com.mchange.v2.resourcepool.BasicResourcePool)at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource()…at org.hibernate.jpa.internal.QueryImpl.getResultList()at domain.funds.FundsRepository.get()…似乎HikariCP的默認(rèn)“ 30秒”要好一些。 不,它在高性能應(yīng)用程序中并沒有真正幫助。 在這30秒內(nèi),可能會(huì)收到許多新請求,并且所有請求都被凍結(jié)。 顯然,應(yīng)用程序?qū)⒑芸焓盏絆utOfMemory錯(cuò)誤。 任何等待只會(huì)將應(yīng)用程序的終止延遲幾秒鐘。
這就是為什么我建議將checkoutTimeout設(shè)置為最小可能值:1ms。 不幸的是,我們不能將其設(shè)置為0,因?yàn)?意味著無盡的等待&#55357;&#56898; 我們越早失敗,我們給工作線程完成工作的機(jī)會(huì)就越大。 而且我們可以清楚地通知用戶該應(yīng)用程序當(dāng)前已超載,他應(yīng)該稍后再試。
在結(jié)帳時(shí)測試連接
有時(shí)池中的連接可能會(huì)死。 數(shù)據(jù)庫可以主動(dòng)關(guān)閉它們,或者系統(tǒng)管理員可以斷開網(wǎng)絡(luò)電纜。 這就是池應(yīng)該監(jiān)視連接活動(dòng)性的原因。
最簡單的設(shè)置是c3p0中的“ testConnectionOnCheckout”(我在HikariCP中沒有找到類似的設(shè)置,它似乎始終處于啟用狀態(tài))。
默認(rèn)值:
| c3p0 | 光ikaCP | 我建議 | |
| testConnectionOnCheckout | 假 | 真正? | 真正 |
當(dāng)然,默認(rèn)情況下應(yīng)該啟用它 !
否則,您將在日志中最終遇到許多此類異常:
org.hibernate.TransactionException: Unable to rollback against JDBC Connection at o.h.r.j.i.AbstractLogicalConnectionImplementor.rollback() at o.h.r.t.b.j.i.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:294)PS如果要獲得更好的性能,可以考慮在后臺而不是在結(jié)帳時(shí)測試連接:
- testConnectionOnCheckout = false
- testConnectionOnCheckin = true
- idleConnectionTestPeriod = 10
首選測試查詢
但是池應(yīng)該如何準(zhǔn)確地測試連接?
問題在于它取決于數(shù)據(jù)庫。
默認(rèn)情況下,兩個(gè)池都通過執(zhí)行以下測試來測試連接
- “ connection.isValid()”(對于JDBC4),或者
- “ connection.getMetaData()。getTables()”(對于JDBC3)
這可能很慢,因?yàn)椤?getTables()”每次都檢索有關(guān)所有表的元信息。 推薦值類似于
- “ SELECT 1”(對于MySql),或者
- “從雙重選擇1”(對于Oracle)等
通過執(zhí)行此簡單而快速的查詢,池可以檢查連接是否仍處于活動(dòng)狀態(tài)。
最大空閑時(shí)間
未使用的連接可以在池中保留多長時(shí)間
- c3p0設(shè)置:maxIdleTime
- HikariCP設(shè)置:idleTimeout
默認(rèn)值:
| c3p0 | 光ikaCP | 我建議 | |
| maxIdleTimeout | ∞ | 10分鐘 | 1..10分鐘 |
可能沒什么大不了的,但是每個(gè)打開的連接
- 在數(shù)據(jù)庫中保存一些資源
- 防止其他系統(tǒng)獲得到同一數(shù)據(jù)庫的連接(每個(gè)數(shù)據(jù)庫都有最大可能連接數(shù)的限制)
因此,關(guān)閉未使用的(空閑)連接是個(gè)好主意。 我建議將此值設(shè)置為無限期。 大概幾分鐘是合理的。
最小泳池大小
應(yīng)始終具有多少個(gè)連接池(即使未使用)。
- c3p0設(shè)置:minPoolSize
- HikariCP設(shè)置:minimumIdle
默認(rèn)值:
| c3p0 | 光ikaCP | 我建議 | |
| maxIdleTimeout | 3 | 最大游泳池 | 0…N |
出于同樣的原因,關(guān)閉未使用的連接可能是一個(gè)好主意。 在大多數(shù)情況下,我會(huì)將此值設(shè)置為0或1。 如果某些用戶意外決定在午夜登錄到您的應(yīng)用程序,那么他將只等待幾毫秒。 沒什么大不了的。
最大連接年齡
連接在池中可以存在多長時(shí)間(無論它是空閑還是已使用)
- c3p0設(shè)置:maxConnectionAge
- HikariCP設(shè)置:maxLifetime
默認(rèn)值:
| c3p0 | 光ikaCP | 我建議 | |
| maxIdleTimeout | ∞ | 30分鐘 | 比方說30分鐘 |
以防萬一,不時(shí)關(guān)閉連接可能是一個(gè)好主意。 可能有助于避免某些內(nèi)存泄漏。
來自HikariCP文檔的報(bào)價(jià):
“我們強(qiáng)烈建議設(shè)置此值,它應(yīng)該比任何數(shù)據(jù)庫或基礎(chǔ)架構(gòu)施加的連接時(shí)間限制短幾秒鐘。”
未返回的連接超時(shí)
典型的問題之一是連接泄漏。 一些錯(cuò)誤的代碼從池中獲取了一個(gè)連接,但沒有返回它。 如何發(fā)現(xiàn)這個(gè)問題?
幸運(yùn)的是,在這種情況下,我們有一個(gè)很好的設(shè)置:
- c3p0設(shè)置:unreturnedConnectionTimeout
- HikariCP設(shè)置:leakDetectionThreshold
默認(rèn)值:
| c3p0 | 光ikaCP | 我建議 | |
| maxIdleTimeout | 殘障人士 | 殘障人士 | 5分鐘? |
如果任何錯(cuò)誤代碼接受了連接但在5分鐘內(nèi)未返回連接,則池將強(qiáng)制返回連接并發(fā)出如下警告:
[C3P0PooledConnectionPoolManager Logging the stack trace by which the overdue resource was checked-out. java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace. at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource() at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1885) at domain.application.ApplicationReportSender.sendWeeklyReport(ApplicationReportSender.java:63)這將幫助您找出有罪代碼在哪里。
結(jié)論
我概述了一些連接池設(shè)置。 還有更多。 根據(jù)我的經(jīng)驗(yàn),我給出了一些合理的建議。 但是您的應(yīng)用程序可能具有不同的負(fù)載。 您的用戶可能會(huì)有不同的行為。 我的建議對您來說似乎很愚蠢。
沒問題。 不要相信我 但也請不要相信默認(rèn)值。
去檢查你的游泳池設(shè)置!
翻譯自: https://www.javacodegeeks.com/2018/12/wtf-connection-pools.html
android wtf
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的android wtf_WTF连接池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 反引号包裹反引号_五个金色反引号
- 下一篇: jakarta ee_在等待Jakart