日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

阿里云sql监控配置-druid

發布時間:2023/11/30 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 阿里云sql监控配置-druid 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? 今天我們說說數據源和數據庫連接池,熟悉java開發的同仁應該都了解C3PO,在這里不做過多的贅述了,今天我們說的是阿里DRUID,druid是后起之秀,因為它的優秀很快占領了使用市場,下邊我們一起來看看druid數據源的配置以及druid監控的配置和監控的實現邏輯。

1、druid數據源配置

? ? ? ?下面是druid的數據源配置項,這些配置項都是com.alibaba.druid.pool.DruidDataSource類和其基類com.alibaba.druid.pool.DruidAbstractDataSource的public final屬性,這些配置型和C3P0的數據源配置項基本一樣,有個別的是明白發生了變化但是參數所表示的意思不變,還有一些參數是druid自己擴展的,其中filters屬性就是杰出代表,次屬性是DruidAbstractDataSource類的,是一個List<Filter>的集合,此屬性提供了三個可選值:監控統計用的stat、日志用的log4j、?防御sql注入的wall,這三個值可以單獨使用也可以兩兩組合或者一起使用,組合使用的時候不同值之間用逗號隔開。有人可能會有疑問了,不是一個List集合嗎,為什么這里卻是用逗號分隔的,那是因為druid在賦值的時候有特殊處理,至于是如何處理的在下邊我們會說到。

配置缺省值說明
name?配置這個屬性的意義在于,如果存在多個數據源,監控的時候
可以通過名字來區分開來。如果沒有配置,將會生成一個名字,
格式是:"DataSource-" + System.identityHashCode(this)
jdbcUrl?連接數據庫的url,不同數據庫不一樣。例如:
mysql : jdbc:mysql://10.20.153.104:3306/druid2?
oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username?連接數據庫的用戶名
password?連接數據庫的密碼。如果你不希望密碼直接寫在配置文件中,
可以使用ConfigFilter。詳細看這里:
https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
driverClassName根據url自動識別這一項可配可不配,如果不配置druid會根據url自動識別dbType,
然后選擇相應的driverClassName
initialSize0初始化時建立物理連接的個數。初始化發生在顯示調用init方法,
或者第一次getConnection時
maxActive8最大連接池數量
maxIdle8已經不再使用,配置了也沒效果
minIdle?最小連接池數量
maxWait?獲取連接時最大等待時間,單位毫秒。配置了maxWait之后,
缺省啟用公平鎖,并發效率會有所下降,
如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。
poolPreparedStatementsfalse是否緩存preparedStatement,也就是PSCache。
PSCache對支持游標的數據庫性能提升巨大,比如說oracle。
在mysql5.5以下的版本中沒有PSCache功能,建議關閉掉。
5.5及以上版本有PSCache,建議開啟。
maxOpenPreparedStatements-1要啟用PSCache,必須配置大于0,當大于0時,
poolPreparedStatements自動觸發修改為true。
在Druid中,不會存在Oracle下PSCache占用內存過多的問題,
可以把這個數值配置大一些,比如說100
validationQuery?用來檢測連接是否有效的sql,要求是一個查詢語句。
如果validationQuery為null,testOnBorrow、testOnReturn、
testWhileIdle都不會其作用。
testOnBorrowtrue申請連接時執行validationQuery檢測連接是否有效,
做了這個配置會降低性能。
testOnReturnfalse歸還連接時執行validationQuery檢測連接是否有效,
做了這個配置會降低性能
testWhileIdlefalse建議配置為true,不影響性能,并且保證安全性。
申請連接的時候檢測,如果空閑時間大于
timeBetweenEvictionRunsMillis,
執行validationQuery檢測連接是否有效。
timeBetweenEvictionRunsMillis?有兩個含義:
1) Destroy線程會檢測連接的間隔時間
?2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明
numTestsPerEvictionRun?不再使用,一個DruidDataSource只支持一個EvictionRun
minEvictableIdleTimeMillis?Destory線程中如果檢測到當前連接的最后活躍時間和當前時間的差值大于
minEvictableIdleTimeMillis,則關閉當前連接。
connectionInitSqls?物理連接初始化的時候執行的sql
exceptionSorter根據dbType自動識別當數據庫拋出一些不可恢復的異常時,拋棄連接
filters?屬性類型是字符串,通過別名的方式配置擴展插件,
常用的插件有:
監控統計用的filter:stat?
日志用的filter:log4j
?防御sql注入的filter:wall
proxyFilters?類型是List<com.alibaba.druid.filter.Filter>,
如果同時配置了filters和proxyFilters,
是組合關系,并非替換關系
removeAbandoned?對于建立時間超過removeAbandonedTimeout的連接強制關閉
removeAbandonedTimeout?指定連接建立多長時間就需要被強制關閉
logAbandoned?指定發生removeabandoned的時候,是否記錄當前線程的堆棧信息到日志中

2、druid監控的配置與監控訪問

?要使用druid監控需要做好兩個配置:

1)、在配置數據源時需要配置filters并且賦值你需要使用的監控項(stat、log4j、wall);

2)、需要在項目的web.xml中配置druid的自定義servlet(com.alibaba.druid.support.http.StatViewServlet),配置樣例如下代碼所示:

<servlet> <servlet-name>DruidStatView</servlet-name> <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DruidStatView</servlet-name> <url-pattern>/druid/*</url-pattern> </servlet-mapping>

3)、監控系統的訪問:http://IP:PORT/projectName/druid/(http://localhost:8088/cd_management/druid/sql.html),監控效果如下圖所示:

3、filters屬性的賦值邏輯

? ? ? ? 上面有提到filters的配置項有三個,可以隨機組合也可以一起使用,也有提到filters是一個List集合,那我們來看看druid是如何賦值的,如下源碼所示,賦值時調用的setFilters(String filters)方法,最終是通過逗號分隔為數組然后遍歷調用FilterManager.loadFilter(this.filters, item.trim()),然后用反射機制生成相應的對象并添加到Filter集合。

public void setFilters(String filters) throws SQLException {if (filters != null && filters.startsWith("!")) { filters = filters.substring(1); this.clearFilters(); } this.addFilters(filters); } public void addFilters(String filters) throws SQLException { if (filters == null || filters.length() == 0) { return; } String[] filterArray = filters.split("\\,"); for (String item : filterArray) { FilterManager.loadFilter(this.filters, item.trim()); } } public static void loadFilter(List<Filter> filters, String filterName) throws SQLException {if (filterName.length() == 0) { return; } String filterClassNames = getFilter(filterName); if (filterClassNames != null) { for (String filterClassName : filterClassNames.split(",")) { if (existsFilter(filters, filterClassName)) { continue; } Class<?> filterClass = Utils.loadClass(filterClassName); if (filterClass == null) { LOG.error("load filter error, filter not found : " + filterClassName); continue; } Filter filter; try { filter = (Filter) filterClass.newInstance(); } catch (ClassCastException e) { LOG.error("load filter error.", e); continue; } catch (InstantiationException e) { throw new SQLException("load managed jdbc driver event listener error. " + filterName, e); } catch (IllegalAccessException e) { throw new SQLException("load managed jdbc driver event listener error. " + filterName, e); } filters.add(filter); } return; } if (existsFilter(filters, filterName)) { return; } Class<?> filterClass = Utils.loadClass(filterName); if (filterClass == null) { LOG.error("load filter error, filter not found : " + filterName); return; } try { Filter filter = (Filter) filterClass.newInstance(); filters.add(filter); } catch (Exception e) { throw new SQLException("load managed jdbc driver event listener error. " + filterName, e); } }

4、druid監控實現邏輯

? ? ?要說明druid監控邏輯從如下三個方面切入分析:

? ? ? 1)、監控的數據什么時候生成

? ? ? ?在這里我們拿Spring和druid整合案例來分析說明druid監控數據的生成,上面我們有提到要使用druid的監控空能需要配置filters,并且filters可以配置多個,這里druid關于這些filter的處理其實借鑒了過濾器鏈的原理,druid關于監控數據的收集處理邏輯是這樣的,我們從Spring的JdbcTemplate類開始看,如下源碼一,是一個查詢的處理,rs = ps.executeQuery()是PreparedStatement開始執行sql從數據庫查詢數據的開始,這里我們給ps對象賦予的是DruidPooledPreparedStatement類對象,所以進入DruidPooledPreparedStatement類我們來看它的具體實現。

? ? ? ? 源碼二是DruidPooledPreparedStatement類對executeQuery方法的實現,這個方法里面最關鍵的是ResultSet rs = stmt.executeQuery()這句,stmt是PreparedStatementProxyImpl類的類對象。

? ? ? ? 源碼三是PreparedStatementProxyImpl類對executeQuery方法的實現,這個方法實現中調用了父類的createChain()方法,源碼四為父類方法實現,這個方法的返回值是一個過濾器鏈類FilterChainImpl類對象,FilterChainImpl類的

preparedStatement_executeQuery(PreparedStatementProxy statement)方法實現如源碼五。

public <T> T query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)throws DataAccessException { Assert.notNull(rse, "ResultSetExtractor must not be null"); logger.debug("Executing prepared SQL query"); return execute(psc, new PreparedStatementCallback<T>() { @Override public T doInPreparedStatement(PreparedStatement ps) throws SQLException { ResultSet rs = null; try { if (pss != null) { pss.setValues(ps); } rs = ps.executeQuery(); ResultSet rsToUse = rs; if (nativeJdbcExtractor != null) { rsToUse = nativeJdbcExtractor.getNativeResultSet(rs); } return rse.extractData(rsToUse); } finally { JdbcUtils.closeResultSet(rs); if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } }); } public ResultSet executeQuery() throws SQLException {checkOpen();incrementExecuteCount();transactionRecord(sql);oracleSetRowPrefetch();conn.beforeExecute();try {ResultSet rs = stmt.executeQuery(); if (rs == null) { return null; } DruidPooledResultSet poolableResultSet = new DruidPooledResultSet(this, rs); addResultSetTrace(poolableResultSet); return poolableResultSet; } catch (Throwable t) { errorCheck(t); throw checkException(t); } finally { conn.afterExecute(); } } public ResultSet executeQuery() throws SQLException {firstResultSet = true;updateCount = null; lastExecuteSql = sql; lastExecuteType = StatementExecuteType.ExecuteQuery; lastExecuteStartNano = -1L; lastExecuteTimeNano = -1L; return createChain().preparedStatement_executeQuery(this); } public FilterChainImpl createChain() {FilterChainImpl chain = this.filterChain;if (chain == null) { chain = new FilterChainImpl(this.getConnectionProxy().getDirectDataSource()); } else { this.filterChain = null; } return chain; } @Overridepublic ResultSetProxy preparedStatement_executeQuery(PreparedStatementProxy statement) throws SQLException {if (this.pos < filterSize) { return nextFilter().preparedStatement_executeQuery(this, statement); } ResultSet resultSet = statement.getRawObject().executeQuery(); if (resultSet == null) { return null; } return new ResultSetProxyImpl(statement, resultSet, dataSource.createResultSetId(), statement.getLastExecuteSql()); }

? ? ? ??看了如上源碼我們會發現FilterChainImpl類的preparedStatement_executeQuery方法執行的時候會先執行過濾器類的此方法,所以我們看看過濾器類做了什么,這里我們拿SQL監控的過濾器類(FilterEventAdapter)來分析,如下源碼是此類的方法實現。我看可以看到此方法先調用了statementExecuteQueryBefore(statement, statement.getSql())方法,然后調用了下一個過濾器類的查詢方法,在方法正常執行以后又調用了statementExecuteQueryAfter(statement, statement.getSql(), resultSet)方法,在方法執行異常的時候調用了statement_executeErrorAfter(statement, statement.getSql(), error),這些方法的作用就是保存SQL執行中的監控數據。說到這里從流程上就說明了druid監控數據的來源。

public ResultSetProxy preparedStatement_executeQuery(FilterChain chain, PreparedStatementProxy statement)throws SQLException {try { statementExecuteQueryBefore(statement, statement.getSql()); ResultSetProxy resultSet = chain.preparedStatement_executeQuery(statement); if (resultSet != null) { statementExecuteQueryAfter(statement, statement.getSql(), resultSet); resultSetOpenAfter(resultSet); } return resultSet; } catch (SQLException error) { statement_executeErrorAfter(statement, statement.getSql(), error); throw error; } catch (RuntimeException error) { statement_executeErrorAfter(statement, statement.getSql(), error); throw error; } catch (Error error) { statement_executeErrorAfter(statement, statement.getSql(), error); throw error; } }

? ? ? 2)、監控的數據保存到哪里

? ? ?這里我們簡單說明,數據是保存到DruidDataSource類的dataSourceStat對象中。

? ? ? 3)、監控的請求如何處理的

? ? ? ? ? ? ? 要使用druid的監控功能需要配置com.alibaba.druid.support.http.StatViewServlet,這是一個繼承自HttpServlet的servlet,用來處理訪問druid監控的請求,具體處理流程如下:

? ? ? ? ?

5、如何去除監控頁面的廣告

? ? ? ?1)?使用過druid的同仁應該都了解,druid的監控頁面加載以后,footer頁是有阿里的廣告的如下圖所示,如果是一個商業項目這個是很不雅也是不允許的,那么我們來看看如何去除廣告。

?

? ? ? ?

? ? ? ?2)要去除這個廣告需要修改druid.jar的源碼文件,具體方法是,用winRAR打開jar包,在druid-1.1.6.jar\support\http\resources\js\common.js路徑下找到文件,修改common.js中如下圖所示的代碼,刪除buildFooter函數中的代碼即可:

buildFooter : function() {var html ='<footer class="footer">'+' <div class="container">'+'<a href="https://render.alipay.com/p/s/taobaonpm_click/druid_banner_click" target="new"><img src="https://render.alipay.com/p/s/taobaonpm_click/druid_banner"></a><br/>' +' powered by <a href="https://github.com/alibaba/" target="_blank">AlibabaTech</a> & <a href="http://www.sandzhang.com/" target="_blank">sandzhang</a> & <a href="http://melin.iteye.com/" target="_blank">melin</a> & <a href="https://github.com/shrekwang" target="_blank">shrek.wang</a>'+' </div>'+' </footer>';$(document.body).append(html);},

轉載于:https://www.cnblogs.com/gu-bin/p/11188917.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的阿里云sql监控配置-druid的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。