- 獲取資源timeout:
異常信息如下:Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
[Cause: com.mchange.v2.resourcepool.TimeoutException:
A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@4d5a39b7 -- timeout at awaitAvailable()
查找發現,獲取connection資源timeout的地方,在basicResourcePool類的awaitAvailable方法里,代碼很簡單:1 private void awaitAvailable(long timeout) throws InterruptedException, TimeoutException, ResourcePoolException 2 { 3 assert Thread.holdsLock( this ); 4 5 if (force_kill_acquires) 6 throw new ResourcePoolException("A ResourcePool cannot acquire a new resource -- the factory or source appears to be down."); 7 8 Thread t = Thread.currentThread(); 9 try 10 { 11 acquireWaiters.add( t ); 12 13 int avail; 14 long start = ( timeout > 0 ? System.currentTimeMillis() : -1); 15 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) 16 { 17 if ( logger.isLoggable( MLevel.FINE ) ) 18 logger.fine("awaitAvailable(): " + 19 (exampleResource != null ? 20 exampleResource : 21 "[unknown]") ); 22 trace(); 23 } 24 while ((avail = unused.size()) == 0) 25 { 26 // the if case below can only occur when 1) a user attempts a 27 // checkout which would provoke an acquire; 2) this 28 // increments the pending acquires, so we go to the 29 // wait below without provoking postAcquireMore(); 3) 30 // the resources are acquired; 4) external management 31 // of the pool (via for instance unpoolResource() 32 // depletes the newly acquired resources before we 33 // regain this' monitor; 5) we fall into wait() with 34 // no acquires being scheduled, and perhaps a managed.size() 35 // of zero, leading to deadlock. This could only occur in 36 // fairly pathological situations where the pool is being 37 // externally forced to a very low (even zero) size, but 38 // since I've seen it, I've fixed it. 39 if (pending_acquires == 0 && managed.size() < max) 40 _recheckResizePool(); 41 42 this.wait(timeout); 43 if (timeout > 0 && System.currentTimeMillis() - start > timeout) 44 throw new TimeoutException("A client timed out while waiting to acquire a resource from " + this + " -- timeout at awaitAvailable()"); 45 if (force_kill_acquires) 46 throw new CannotAcquireResourceException("A ResourcePool could not acquire a resource from its primary factory or source."); 47 ensureNotBroken(); 48 } 49 } 50 finally 51 { 52 acquireWaiters.remove( t ); 53 if (acquireWaiters.size() == 0) 54 this.notifyAll(); 55 } 56 }
拋出異常的是第44行,而拋出異常的先決條件就是timeout了。表象來看是這樣,再繼續跟進代碼的時候發現,進入等待資源的先決條件是:
1、available==0(unused==0) 2、managed。size>=max(池數量已達到最大) 3、獲取到的資源異常:如果設置了checkedoutTest這一項時,進行test的時候失敗,導致異常;
所以更直接的原因是以下幾種:
1、請求資源的隊列太長,排隊時間太長導致超時:線程數量應付不過來大量的請求數量,導致超時 2、testConnection的原因導致的異常:網絡震盪 3、數據庫服務器端無更多的鏈接可用
那么相應的解決方案:
1、請求資源過長的,加大maxsize,如果請求量過大的,盡量將min和max設置成一個值,因此不存在shrink和expand的操作,這也是一種性能消耗 2、testConnection設置在checkin即可,checkout時無需test,否則卡在網絡震盪就不好了 3、檢查數據庫端的最大鏈接數。 4、將c3p0的debug日志打開,檢查它的managed、unused、available的分別size
- deadlock