有客戶(hù)說(shuō),他們通過(guò)connection pool監控發(fā)現weblogic92連接池中當前連接數(current capacity)小于初始連接數(initial capacity)。從現象上來(lái)說(shuō),給客戶(hù)的直覺(jué)是:連接池初始化有問(wèn)題,沒(méi)有幫助他們初始化他們需要的那么多連接。但他同時(shí)發(fā)現,幾個(gè) connection pool中,其他pool沒(méi)有問(wèn)題。拿到問(wèn)題,我也懷疑這可能是weblogic的一個(gè)bug,但隨后從客戶(hù)發(fā)送過(guò)來(lái)的日志中發(fā)現出問(wèn)題的 connection被disable過(guò)。調查后發(fā)現問(wèn)題的確和這個(gè)pool被disable過(guò)有關(guān),那么為什么pool被disable后,會(huì )出現這樣的問(wèn)題呢?
首先我們看看這個(gè)pool為什么會(huì )被disable? 手工強制suspend連接池、數據庫關(guān)閉、網(wǎng)絡(luò )不穩定等因素都可能成為connection pool被disable的誘因。從客戶(hù)的日志中,我能看到大量的如下異常,
1:java.net.SocketException: 管道已斷開(kāi) (errno:32)
2:weblogic.common.resourcepool.ResourceDisabledException: Pool JDBC Data Source-0 is disabled, cannot allocate resources to applications.
根據上面的異常,首先跟客戶(hù)確認是否存在過(guò)數據庫關(guān)閉、強制disable connection的操作,這些都被客戶(hù)否定了,那么最大可能的原因就是網(wǎng)絡(luò )不穩定,網(wǎng)絡(luò )是好時(shí)壞的話(huà),很容易造成weblogic連接池中到 database server的連接中斷,從而導致connection pool被disable。
那么為什么連接中斷會(huì )引起connection pool被disable呢?這里要談到兩個(gè)參數:CountOfTestFailuresTillFlush、 CountOfRefreshFailuresTillDisable。這兩個(gè)參數在weblogic連接池實(shí)現中由于控制是否、何時(shí)flush或 disable連接池,兩個(gè)都是指連續幾次失敗操作(test、refresh)后去flush或disable connection pool。注意:這是說(shuō)的是連續,而不是間斷,每次成功操作(test、refresh)后,這兩個(gè)值都會(huì )被reset成0。默認情況下這兩個(gè)值均為2,即連續失敗3(2+1)次后,connection pool會(huì )被flush或disable。兩者的區別在于,flush用于清空connection pool中的所有連接(通常都是中斷的connection),當pool狀態(tài)仍保持在running狀態(tài),而對于后者,connection pool將會(huì )變成suspend。前者對于客戶(hù)端而言,還可以從pool中reserve connection,reserve時(shí),weblogic會(huì )嘗試重現創(chuàng )建連接,如果創(chuàng )建連接成功,那么客戶(hù)端就可以拿到可用的連接。而對于一個(gè)處于 suspend狀態(tài),客戶(hù)端reserve connection的請求會(huì )直接被拒絕,收到的異常如下:
weblogic.common.resourcepool.ResourceDisabledException: Pool JDBC Data Source-0 is disabled, cannot allocate resources to applications
一個(gè)被disable的connection pool我們需要手工resume嗎?比如數據庫因為某些原因而突發(fā)關(guān)閉,數據庫恢復后,我們是否需要手工去resume這個(gè)pool?不需要,weblogic內部實(shí)現了連接池的自我健康檢查功能,對于disable的connection pool,weblogic會(huì )每隔5秒鐘(DEFAULT_SCAN_UNIT)去做一次連接嘗試(嘗試創(chuàng )建一個(gè)物理連接,如果連接成功,那么這個(gè)連接會(huì )被直接放入連接池中,我們的問(wèn)題就處在這兒),我們通過(guò)下面的復現過(guò)程來(lái)看看具體原因:
1:配置一個(gè)datasource,connection的連接數具體配置如下:
圖片看不清楚?請點(diǎn)擊這里查看原圖(大圖)。
2:weblogic啟動(dòng)后,我們可以看到current capacity為15,此時(shí)connection pool剛被初始化,weblogic會(huì )根據initial capacity去創(chuàng )建相應數量的連接。此時(shí)如果我們關(guān)閉數據庫,然后通過(guò)測試程序去獲取連接,你會(huì )看到我們無(wú)法拿到連接(注意我們要選上 TestOnReserve),重復三次,再次去監控connection pool。因為三次test失敗后,connection pool會(huì )被disable(狀態(tài)為suspend),如下:
3:重啟database。由于weblogic內部實(shí)現了connection pool的自檢功能,對于disabled的connection pool,weblogic每隔5秒鐘去做一次連接嘗試,如果連接創(chuàng )建成功,新建連接會(huì )被放入連接池,同時(shí)resume連接池。通過(guò)監控我們可以看到,連接池狀態(tài)變成running,同時(shí)current capacity變成1,
圖片看不清楚?請點(diǎn)擊這里查看原圖(大圖)。
圖片看不清楚?請點(diǎn)擊這里查看原圖(大圖)。
4:?jiǎn)?dòng)多線(xiàn)程測試程序,模擬2個(gè)用戶(hù)并發(fā)。第一個(gè)用戶(hù)可以從connection pool中成功拿到連接,而第二個(gè)用戶(hù)因為連接池的current capacity為1,無(wú)法直接從pool中拿到連接,這是連接池需要做擴展,而擴展的個(gè)數就是我們設定的capacity increment(20)。再來(lái)監控connection pool,我們就會(huì )看到連接池的current capacity為21,如下:
圖片看不清楚?請點(diǎn)擊這里查看原圖(大圖)。
那么我們能不能通過(guò)參數配置不讓connection pool不作disable呢?我們前面所提到的兩個(gè)參數:CountOfTestFailuresTillFlush、 CountOfRefreshFailuresTillDisable,可以實(shí)現這樣的要求:
1 <internal-properties>
2 <property>
3 <name>CountOfTestFailuresTillFlush</name>
4 <value>10</value>
5 </property>
6 <property>
7 <name>CountOfRefreshFailuresTillDisable</name>
8 <value>20</value>
9 </property>
10 </internal-properties>
internal-properties用于定義一些weblogic internal的參數,這些參數無(wú)法在console上做配置。除了上面的這兩個(gè)參數,我們還可以通過(guò)internal-properties配置如下幾個(gè)參數:
TestConnectionsOnCreate
TestConnectionsOnRelease
HighestNumUnavailable
SecurityCacheTimeoutSeconds
通過(guò)上述分析,我們可以看到這個(gè)問(wèn)題不是weblogic的bug,而是因為網(wǎng)絡(luò )問(wèn)題導致connection pool被disable,要徹底解決這個(gè)問(wèn)題,可以通過(guò)網(wǎng)絡(luò )分析工具查出網(wǎng)絡(luò )問(wèn)題,進(jìn)而解決我們看到的這種現象。