1. 程式人生 > >DBCP 應用的總結(一)

DBCP 應用的總結(一)

DBCP 應用的總結
1.Jar包下載

首先,下載必須的jar包 

dbcp包:http://jakarta.apache.org/commons/dbcp/ 

pool包:http://jakarta.apache.org/commons/pool/, 

如果下載的pool包是1.2的版本,還要下載common-collections包:

2.配置引數
username : 連線使用者名稱

password:  連線密碼

url :  連線 url( 如果連線 mysql ,格式為 jdbc:mysql://ip:port/dbname)

driverClassName : jdbc driver 名字 ( 如果是 mysql ,則為com.mysql.jdbc.Driver)

connectionProperties : 當建立一個數據庫連線的時候,這些屬性引數將傳給 jdbc driver ,引數的形式必須是 [propertyName=property;]*  。

注: username 和 password 必須明確的傳給 driver, 不必包含在這個屬性中。

initialSize : 預設值是 0, 連線池建立連線的初始連線數目

maxActive : 預設值是 8, 連線池中同時可以分派的最大活躍連線數

maxIdle : 預設是 8 ,連線池中最大空閒連線數

minIdle : 預設是 0, 連線數中最小空閒連線數

maxWait : 預設值是無限大,當連線池中連線已經用完了,等待建立一個新連線的最大毫秒數 ( 在拋異常之前 )

validationQuery : 一條 sql 語句,用來驗證資料庫連線是否正常。這條語句必須是一個查詢模式,並至少返回一條資料。一般用“ select 1 ”

testOnBorrow : 預設值是 true ,當從連線池取連線時,驗證這個連線是否有效

testOnReturn : 預設值是 flase, 當從把該連線放回到連線池的時,驗證這個連線是否有效

testWhileIdle : 預設值是 false, 當連線池中的空閒連線是否有效

timeBetweenEvictionRunsMilis : 預設值是 -1 ,每隔一段多少毫秒跑一次回收空閒執行緒的執行緒

numTestsPerEvictionRun : 預設值是 3 ,每次驗證空閒連線的連線數目

minEvictableIdleTimeMilis : 預設值是 1000 * 60 * 30(30 分鐘 ) ,連線池中連線可空閒的時間

connectionInitSqls : 預設值是 null, 一組用來初始化連線的 sql 語句,這些語句只在連線工廠建立連線時執行一次。

removeAbandoned : 預設值是 false, 是否清理 removeAbandonedTimeout 秒沒有使用的活動連線 , 清理後並沒有放回連線池  

removeAbandonedTimeout : 預設值是 300( 秒 ), 活動連線的最大空閒時間

logAbandoned : 預設值 false, 連線池收回空閒的活動連線時是否列印訊息

注:

1. 紅色字型的屬性一般都會設定

2.   minEvictableIdleTimeMilis,removeAbandonedTimeout 這兩個引數針對的連線物件不一樣,minEvictableIdleTimeMillis 針對連線池中的連線物件 ,removeAbandonedTimeout 針對未被 close 的活動連線 (被呼叫,不在池中的連線物件 )

3.   maxWait 、 timeBetweenEvictionRunsMilis 、 minEvictableIdleTimeMilis 單位是毫秒,removeAbandonedTimeout 單位是秒

3. 異常處理
dbcp是採用了commons-pool做為其連線池治理,testOnBorrow,testOnReturn, testWhileIdle是pool是提供的幾種校驗機制,通過外部鉤子的方式回撥dbcp的相關資料庫連結(validationQuery)校驗 
testOnBorrow : 顧明思義,就是在進行borrowObject進行處理時,對拿到的connection進行validateObject校驗 
testOnReturn : 顧明思義,就是在進行returnObject對返回的connection進行validateObject校驗,個人覺得對資料庫連線池的治理意義不大 
testWhileIdle : 關注的重點,GenericObjectPool中針對pool治理,起了一個Evict的TimerTask定時執行緒進行控制(可通過設定引數timeBetweenEvictionRunsMillis>0),定時對執行緒池中的連結進行validateObject校驗,對無效的連結進行封閉後,會呼叫ensureMinIdle,適當建立連結保證最小的minIdle連線數。 
timeBetweenEvictionRunsMillis,設定的Evict執行緒的時間,單位ms,大於0才會開啟evict檢查執行緒
validateQuery, 代表檢查的sql 
validateQueryTimeout, 代表在執行檢查時,通過statement設定,statement.setQueryTimeout(validationQueryTimeout) 
numTestsPerEvictionRun,代表每次檢查連結的數目,建議設定和maxActive一樣大,這樣每次可以有效檢查所有的連結. 

資料庫連結 常見的問題:

1. 資料庫意外重啟後,原先的資料庫連線池能自動廢棄老的無用的連結,建立新的資料庫連結

2. 網路異常中斷後,原先的建立的 tcp 連結,應該能進行自動切換。比如網站演習中的交換機重啟會導致網路瞬斷

3. 分散式資料庫中介軟體,會定時的將空閒連結異常關閉,客戶端會出現半開的空閒連結。

大致思考解決思路:

1.      sql 心跳檢查 ( 主動式 )

2.      拿連結嘗試一下,發現處理失敗丟棄連結,探雷的請求會失敗幾個  ( 犧牲小我,完成大我的精神 )

3.      設定合理的空閒連結的超時時間,避免半開連結 ( 懶模式,解決半開連結 )


sql 心跳檢查

sql validate 配置

<property name= "testWhileIdle" ><value> true </value></property>

<property name= "testOnBorrow" ><value> false </value></property>

<property name= "testOnReturn" ><value> false </value></property>

<property name= "validationQuery" ><value>select sysdate from dual</value></property>

<property name= "validationQueryTimeout" ><value>1</value></property>

<property name= "timeBetweenEvictionRunsMillis" ><value>30000</value></property>

<property name= "numTestsPerEvictionRun" ><value>16</value></property>

引數說明

   dbcp 是採用了 commons-pool 做為其連線池管理, testOnBorrow,testOnReturn, testWhileIdle 是 pool 是提供的幾種校驗機制,通過外部鉤子的方式回撥 dbcp 的相關資料庫連結 (validationQuery) 校驗 , dbcp 相關外部鉤子類: PoolableConnectionFactory, 繼承於 common-pool PoolableObjectFactory , dbcp 通過GenericObjectPool 這一入口,進行連線池的 borrow,return 處理。

具體引數描述:

   1. testOnBorrow : 顧明思義,就是在進行borrowObject進行處理時,對拿到的connection進行validateObject校驗

   2. testOnReturn : 顧明思義,就是在進行returnObject對返回的connection進行validateObject校驗,個人覺得對資料庫連線池的管理意義不大

   3. testWhileIdle : 關注的重點,GenericObjectPool中針對pool管理,起了一個 非同步Evict的TimerTask定時執行緒進行控制 ( 可通過設定引數 timeBetweenEvictionRunsMillis>0), 定時對執行緒池中的連結進行validateObject校驗,對無效的連結進行關閉後,會呼叫ensureMinIdle,適當建立連結保證最小的minIdle連線數。

   4. timeBetweenEvictionRunsMillis, 設定的Evict執行緒的時間,單位ms,大於0才會開啟evict檢查執行緒

   5. validateQuery , 代表檢查的sql

   6. validateQueryTimeout , 代表在執行檢查時,通過statement設定,statement.setQueryTimeout(validationQueryTimeout)

   7. numTestsPerEvictionRun ,代表每次檢查連結的數量,建議設定和maxActive一樣大,這樣每次可以有效檢查所有的連結.

Sql 心跳檢查幾點思考:

1. 效能問題。

目前網站的應用大部分的瓶頸還是在I/O這一塊,大部分的I/O還是在資料庫的這一層面上,每一個請求可能會呼叫10來次SQL查詢,如果不走事務,一個請求會重複獲取連結,如果每次獲取連結,比如在testOnBorrow都進行validateObject,效能開銷不是很能接受,可以假定一次SQL操作消毫0.5~1ms(一般走了網路請求基本就這數)

2 .成本和收益

網站異常資料庫重啟,網路異常斷開的頻率是非常低的,一般也就在資料庫升級,演習維護時才會進行,而且一般也是選在晚上,訪問量相對比較低的請求,而且一般會有人員值班關注,所以非同步的validateObject是可以接受,但一個前提需要確保能保證在一個合理的時間段內,資料庫能完成自動重聯。

請求探雷

相關配置

dbcp 自身預設支援,不需要配置

原理描述

common-pools 通過borrowObject , returnObject完成連線的獲取和釋放,正常的情況是一次請求中borrow和return是一對的,有借就有還。

但在準備returnObject時,dbcp會做一件事,就是看看這個object是否已經是壞了的,如果壞了就直接丟了,就直接給丟棄了。

程式碼層面:

1. 在dbcp中PoolingDataSource(實現DataSource介面)呼叫 PoolableConnection(dbcp connnection 相關的pool delegate操作)進行相應關閉時,會檢查 _conn.isClosed() ,針對DataSource如果isClosed返回為 true的則不呼叫returnObject,直接丟棄了連結。

2. _conn.isClosed()是否保險,從jdk的api描述中: A connection is closed if the method close has been called on it or if certain fatal errors have occurred. 裡面提供兩種情況,一種就是被呼叫了closed方法,另一種就是出現一些異常,說的比較含糊。

空閒連結檢查

相關配置

<property name="minEvictableIdleTimeMillis "><value>18000000</value></property>

<property name="removeAbandoned" ><value>true</value></property> 

<property name="removeAbandonedTimeout "><value>180</value></property>

引數說明

1. minEvictableIdleTimeMillis  dbcp預設是30分,需要開啟非同步執行緒Evict,否則不生效。原理很簡單,就是通過一個非同步執行緒,每次檢查connnection上一次使用的時間戳,看看是否已經超過這個timeout時間設定。

2. removeAbandoned , removeAbandonedTimeout ,主要是用於在出現連結緊張時候,會掃描一些連結未超過removeAbandonedTimeout時間還未被釋放,會主動的關閉該連結。

適用情況

1. 我們使用的cobar後端會有定時關閉空閒連結的操作,預設的空閒連結timeout時間為1小時,和其他oracle , mysql 各不相同,所以設定好這個空閒連結的timeout時間還是挺重要.

2. 一般會是幾種情況出現需要removeAbandoned: 

* 程式碼未在finally釋放connection ,  不過我們都用sqlmapClientTemplate,底層都有連結釋放的過程

* 遇到資料庫死鎖 。以前遇到過後端儲存過程做了鎖表操作,導致前臺叢集中連線池全都被block住,後續的業務處理因為拿不到連結所有都處理失敗了

4.例子

config.properties


#DB Config
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://10.103.8.14:53306/search?useUnicode=true&characterEncoding=utf-8
username=root
password=8bewp2rJHfRGrl9VTQmc
initialSize=1
minIdle=1
maxIdle=10
maxActive=100
#代表當Connection用盡了,多久之後進行回收丟失連線 
maxWait=1000
#是否自動回收超時連線
removeAbandoned=true
#超時等待時間以毫秒為單位
removeAbandonedTimeout=300
#是否在自動回收超時連線的時候列印連線的超時錯誤
logAbandoned=true
程式碼:


public static void init() throws Exception {
    InputStream is = JDBCHelper.class.getClassLoader().getResourceAsStream("config.properties"); 
    Properties prop = new Properties(); 
        
    try {
        prop.load(is);
        ds = BasicDataSourceFactory.createDataSource(prop);
    } catch (SQLException e) {
        e.printStackTrace();
        throw e;
    }
}
    
public Connection getConnection() throws SQLException {
    Connection con = null;
    con = ds.getConnection();
    return con;
}