agapple

          BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
            13 Posts :: 1 Stories :: 1 Comments :: 0 Trackbacks

          2010年10月23日 #

               摘要: 背景     前段時(shí)間在工作中,包括一些代碼閱讀過(guò)程中,spring aop經(jīng)常性的會(huì)看到cglib中的相關(guān)內(nèi)容,包括BeanCopier,BulkBean,Enancher等內(nèi)容,以前雖大致知道一些內(nèi)容,原理是通過(guò)bytecode,但沒(méi)具體深入代碼研究,只知其所用不知其所以然,所以就特地花了半天多的工作時(shí)間研究了CGLIB的相關(guān)源碼,同時(shí)結(jié)合看了下 spring ...  閱讀全文
          posted @ 2010-11-01 22:24 agapple 閱讀(1318) | 評(píng)論 (0)編輯 收藏

             最近在做offerdetail優(yōu)化時(shí),替換了數(shù)據(jù)庫(kù)驅(qū)動(dòng),從c3p0 0.9.1 -> dbcp 1.4順便研究了下dbcp的自動(dòng)重連的一套機(jī)制,也做一下分享,大家周知一下。

           

          數(shù)據(jù)庫(kù)鏈接 常見(jiàn)的問(wèn)題:

          1. 數(shù)據(jù)庫(kù)意外重啟后,原先的數(shù)據(jù)庫(kù)連接池能自動(dòng)廢棄老的無(wú)用的鏈接,建立新的數(shù)據(jù)庫(kù)鏈接

          2. 網(wǎng)絡(luò)異常中斷后,原先的建立的tcp鏈接,應(yīng)該能進(jìn)行自動(dòng)切換。比如網(wǎng)站演習(xí)中的交換機(jī)重啟會(huì)導(dǎo)致網(wǎng)絡(luò)瞬斷

          3. 分布式數(shù)據(jù)庫(kù)中間件,比如cobar會(huì)定時(shí)的將空閑鏈接異常關(guān)閉,客戶端會(huì)出現(xiàn)半開(kāi)的空閑鏈接。

           

          大致思考解決思路:

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

          2.      拿鏈接嘗試一下,發(fā)現(xiàn)處理失敗丟棄鏈接,探雷的請(qǐng)求會(huì)失敗幾個(gè) (犧牲小我,完成大我的精神)

          3.      設(shè)置合理的空閑鏈接的超時(shí)時(shí)間,避免半開(kāi)鏈接(懶模式,解決半開(kāi)鏈接)

           

           

          下面我們來(lái)看看,在dbcp中是如何實(shí)現(xiàn)。

          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>

          參數(shù)說(shuō)明

            

             dbcp是采用了commons-pool做為其連接池管理,testOnBorrow,testOnReturn, testWhileIdlepool是提供的幾種校驗(yàn)機(jī)制,通過(guò)外部鉤子的方式回調(diào)dbcp的相關(guān)數(shù)據(jù)庫(kù)鏈接(validationQuery)校驗(yàn), dbcp相關(guān)外部鉤子類:PoolableConnectionFactory,繼承于common-pool PoolableObjectFactory , dbcp通過(guò)GenericObjectPool這一入口,進(jìn)行連接池的borrow,return處理。

          具體參數(shù)描述:

             1. testOnBorrow : 顧明思義,就是在進(jìn)行borrowObject進(jìn)行處理時(shí),對(duì)拿到的connection進(jìn)行validateObject校驗(yàn)

             2. testOnReturn : 顧明思義,就是在進(jìn)行returnObject對(duì)返回的connection進(jìn)行validateObject校驗(yàn),個(gè)人覺(jué)得對(duì)數(shù)據(jù)庫(kù)連接池的管理意義不大

             3. testWhileIdle : 關(guān)注的重點(diǎn),GenericObjectPool中針對(duì)pool管理,起了一個(gè)異步Evict的TimerTask定時(shí)線程進(jìn)行控制(可通過(guò)設(shè)置參數(shù) timeBetweenEvictionRunsMillis>0),定時(shí)對(duì)線程池中的鏈接進(jìn)行validateObject校驗(yàn),對(duì)無(wú)效的鏈接進(jìn)行關(guān)閉后,會(huì)調(diào)用ensureMinIdle,適當(dāng)建立鏈接保證最小的minIdle連接數(shù)。

             4. timeBetweenEvictionRunsMillis,設(shè)置的Evict線程的時(shí)間,單位ms,大于0才會(huì)開(kāi)啟evict檢查線程

             5. validateQuery, 代表檢查的sql

             6. validateQueryTimeout, 代表在執(zhí)行檢查時(shí),通過(guò)statement設(shè)置,statement.setQueryTimeout(validationQueryTimeout)

             7. numTestsPerEvictionRun,代表每次檢查鏈接的數(shù)量,建議設(shè)置和maxActive一樣大,這樣每次可以有效檢查所有的鏈接.

          Sql心跳檢查幾點(diǎn)思考:

          1.性能問(wèn)題。

          目前網(wǎng)站的應(yīng)用大部分的瓶頸還是在I/O這一塊,大部分的I/O還是在數(shù)據(jù)庫(kù)的這一層面上,每一個(gè)請(qǐng)求可能會(huì)調(diào)用10來(lái)次SQL查詢,如果不走事務(wù),一個(gè)請(qǐng)求會(huì)重復(fù)獲取鏈接,如果每次獲取鏈接,比如在testOnBorrow都進(jìn)行validateObject,性能開(kāi)銷不是很能接受,可以假定一次SQL操作消毫0.5~1ms(一般走了網(wǎng)絡(luò)請(qǐng)求基本就這數(shù))

          2.成本和收益

          網(wǎng)站異常數(shù)據(jù)庫(kù)重啟,網(wǎng)絡(luò)異常斷開(kāi)的頻率是非常低的,一般也就在數(shù)據(jù)庫(kù)升級(jí),演習(xí)維護(hù)時(shí)才會(huì)進(jìn)行,而且一般也是選在晚上,訪問(wèn)量相對(duì)比較低的請(qǐng)求,而且一般會(huì)有人員值班關(guān)注,所以異步的validateObject是可以接受,但一個(gè)前提需要確保能保證在一個(gè)合理的時(shí)間段內(nèi),數(shù)據(jù)庫(kù)能完成自動(dòng)重聯(lián)。

           

          請(qǐng)求探雷

          相關(guān)配置

          dbcp自身默認(rèn)支持,不需要配置

          原理描述

          common-pools通過(guò)borrowObject , returnObject完成連接的獲取和釋放,正常的情況是一次請(qǐng)求中borrow和return是一對(duì)的,有借就有還。

          但在準(zhǔn)備returnObject時(shí),dbcp會(huì)做一件事,就是看看這個(gè)object是否已經(jīng)是壞了的,如果壞了就直接丟了,就直接給丟棄了。

           

          代碼層面:

          1. 在dbcp中PoolingDataSource(實(shí)現(xiàn)DataSource接口)調(diào)用 PoolableConnection(dbcp connnection相關(guān)的pool delegate操作)進(jìn)行相應(yīng)關(guān)閉時(shí),會(huì)檢查_conn.isClosed(),針對(duì)DataSource如果isClosed返回為 true的則不調(diào)用returnObject,直接丟棄了鏈接。

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

           

          空閑鏈接檢查

          相關(guān)配置

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

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

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

          參數(shù)說(shuō)明

          1.minEvictableIdleTimeMillis dbcp默認(rèn)是30分,需要開(kāi)啟異步線程Evict,否則不生效。原理很簡(jiǎn)單,就是通過(guò)一個(gè)異步線程,每次檢查connnection上一次使用的時(shí)間戳,看看是否已經(jīng)超過(guò)這個(gè)timeout時(shí)間設(shè)置。

          2. removeAbandoned , removeAbandonedTimeout,主要是用于在出現(xiàn)鏈接緊張時(shí)候,會(huì)掃描一些鏈接未超過(guò)removeAbandonedTimeout時(shí)間還未被釋放,會(huì)主動(dòng)的關(guān)閉該鏈接。

          適用情況

          1. 我們使用的cobar后端會(huì)有定時(shí)關(guān)閉空閑鏈接的操作,默認(rèn)的空閑鏈接timeout時(shí)間為1小時(shí),和其他oracle , mysql各不相同,所以設(shè)置好這個(gè)空閑鏈接的timeout時(shí)間還是挺重要.

           

          2. 一般會(huì)是幾種情況出現(xiàn)需要removeAbandoned: 

          * 代碼未在finally釋放connection , 不過(guò)我們都用sqlmapClientTemplate,底層都有鏈接釋放的過(guò)程

          * 遇到數(shù)據(jù)庫(kù)死鎖。以前遇到過(guò)后端存儲(chǔ)過(guò)程做了鎖表操作,導(dǎo)致前臺(tái)集群中連接池全都被block住,后續(xù)的業(yè)務(wù)處理因?yàn)槟貌坏芥溄铀卸继幚硎×恕?/span>

           

           

          聊聊c3p0配置

          還有我們配置的c3p0所謂的自動(dòng)重連的3個(gè)參數(shù),

          <prop key="acquireRetryAttempts">30</prop>

              <prop key="acquireRetryDelay">1000</prop>

              <prop key="breakAfterAcquireFailure">false</prop>

           

          個(gè)人覺(jué)得就是一個(gè)誤導(dǎo),這幾個(gè)配置只是在從連接池獲取鏈接時(shí),獲取失敗多嘗試幾次,因?yàn)槲覀儚膒ool從獲取鏈接最多只會(huì)等待固定timeout時(shí)間。

          如果要達(dá)到自動(dòng)重連的效果,必須要c3p0支持請(qǐng)求探雷或者是sql心跳檢查功能,能自動(dòng)的剔除無(wú)效的鏈接。 

          可見(jiàn)c3p0官方文檔描述:http://www.mchange.com/projects/c3p0/index.html#configuring_recovery

           

          最后:

          Dbcp將是我們以后數(shù)據(jù)庫(kù)驅(qū)動(dòng)選擇的趨勢(shì),最后我們?nèi)绾芜x擇如何自動(dòng)重連,這個(gè)也得根據(jù)我們的應(yīng)用場(chǎng)景而定。比如只讀的web系統(tǒng),后臺(tái)業(yè)務(wù)系統(tǒng),任務(wù)系統(tǒng)可能處理方式就不同。

          只讀Web系統(tǒng):可采取請(qǐng)求探雷的策略,也就失敗連接池個(gè)數(shù)的請(qǐng)求,失敗了頁(yè)面刷新一次就好。

          后臺(tái)業(yè)務(wù)系統(tǒng):一般業(yè)務(wù)都涉及數(shù)據(jù)庫(kù)的寫(xiě)操作,很多數(shù)據(jù)不可重入,一次處理失敗后就只能靠手工干預(yù)處理。這時(shí)候得考慮是否需要使用sql心跳檢查,比如testOnBorrow或者testWhileIdle.

          posted @ 2010-10-23 01:01 agapple 閱讀(961) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 潞城市| 洛隆县| 大洼县| 陕西省| 车致| 扶余县| 浦东新区| 潜江市| 蓝山县| 上蔡县| 大庆市| 金湖县| 贺兰县| 建阳市| 金山区| 大同县| 色达县| 民和| 保康县| 民丰县| 盘山县| 桃江县| 安顺市| 民和| 天气| 榆树市| 抚州市| 南康市| 炉霍县| 四川省| 凤冈县| 新田县| 西平县| 崇仁县| 京山县| 余江县| 临汾市| 佛学| 梓潼县| 利津县| 车致|