1. 程式人生 > >Druid連接池(二)

Druid連接池(二)

文件配置 所有 輸入 current 一次 基本 情況 area 分析

六、Druid關聯

  6.1、Web關聯監控配置

  WebStatFilter用於采集web-jdbc關聯監控的數據。

  web.xml配置:

<filter>    
   <filter-name>DruidWebStatFilter</filter-name>
     <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
     <init-param>
         <param-name>exclusions</param-name>
         <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
</param-value>
     </init-param>
</filter>
<filter-mapping>
   <filter-name>DruidWebStatFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

  exlusions配置:

  經常需要排除一些不必要的url,比如.js,/jslib/等等。配置在init-param中。比如:

<init-param>        
    <param-name>exclusions</param-name>
    <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
</param-value>
</init-param>

  sessionStatMaxCount配置:  

  缺省sessionStatMaxCount是1000個。你可以按需要進行配置,比如:

<init-param>        
    <param-name>sessionStatMaxCount</param-name>
    <param-value>1000</param-value>
</init-param>

  sessionStatEnable配置:

  你可以關閉session統計功能,比如:

<init-param>        
    <param-name>sessionStatEnable</param-name>
    <param-value>false</param-value>
</init-param>

  principalSessionName配置:

  你可以配置principalSessionName,使得druid能夠知道當前的session的用戶是誰。比如:

<init-param>        
    <param-name>principalSessionName</param-name>
    <param-value>xxx.user</param-value>
</init-param>

  根據需要,把其中的xxx.user修改為你user信息保存在session中的sessionName。

  註意:如果你session中保存的是非string類型的對象,需要重載toString方法。

  principalCookieName:

  如果你的user信息保存在cookie中,你可以配置principalCookieName,使得druid知道當前的user是誰

<init-param>        
    <param-name>principalCookieName</param-name>
    <param-value>xxx.user</param-value>
</init-param>

  根據需要,把其中的xxx.user修改為你user信息保存在cookie中的cookieName

  profileEnable:

  druid 0.2.7版本開始支持profile,配置profileEnable能夠監控單個url調用的sql列表。

<init-param>    
    <param-name>profileEnable</param-name>
    <param-value>true</param-value>
</init-param>

技術分享圖片

技術分享圖片

  6.2.Spring關聯監控配置

   Druid提供了Spring和Jdbc的關聯監控。

   配置spring

com.alibaba.druid.support.spring.stat.DruidStatInterceptor是一個標準的Spring MethodInterceptor。

  靈活進行AOP配置。

  Spring AOP的配置文檔:

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop-api.html

  按類型攔截配置:

<bean id="druid-stat-interceptor"    class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">  
</bean>
<bean id="druid-type-proxyCreator" class="com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator">
    <!-- 所有ABCInterface的派生類被攔截監控 -->
    <property name="targetBeanType" value="xxxx.ABCInterface" />
    <property name="interceptorNames">
      <list>
        <value>druid-stat-interceptor</value>
      </list>
    </property>
</bean>

  方法名正則匹配攔截配置:

<bean id="druid-stat-interceptor"    class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">  
</bean>
<bean id="druid-stat-pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">
    <property name="patterns">
      <list>
         <value>com.mycompany.service.*</value>
         <value>com.mycompany.dao.*</value>
      </list>
    </property>
</bean>
<aop:config>
    <aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" />
</aop:config>

  有些情況下,可能你需要配置proxy-target-class,例如:

<aop:config proxy-target-class="true">    
    <aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" />
</aop:config>

  按照BeanId來攔截配置:

<bean id="druid-stat-interceptor"    class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">  
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="proxyTargetClass" value="true" />
    <property name="beanNames">
      <list>
        <!-- 這裏配置需要攔截的bean id列表 -->
        <value>xxx-dao</value>
        <value>xxx-service</value>
      </list>
    </property>
    <property name="interceptorNames">
      <list>
        <value>druid-stat-interceptor</value>
      </list>
    </property>
</bean>

七、Druid防禦

  Druid提供了WallFilter,它是基於SQL語義分析來實現防禦SQL註入攻擊的。

  這個文檔提供基於Spring的各種配置方式。

  使用缺省配置的WallFilter:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">      
    ...
    <property name="filters" value="wall"/>
</bean>

  結合其他Filter一起使用:

  WallFilter可以結合其他Filter一起使用,例如:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">      
    ...
    <property name="filters" value="wall,stat"/>
</bean>

  這樣,攔截檢測的時間不在StatFilter統計的SQL執行時間內。

  如果希望StatFilter統計的SQL執行時間內,則使用如下配置:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">      
    ...
    <property name="filters" value="stat,wall"/>
</bean>

  指定dbType

 有時候,一些應用框架做了自己的JDBC Proxy Driver,是的DruidDataSource無法正確識別數據庫的類型,則需要特別指定,如下:

<bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">      
    <property name="dbType" value="mysql" />
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    ...
    <property name="proxyFilters">
      <list>
        <ref bean="wall-filter"/>
      </list>
    </property>
</bean>

  指定配置裝載的目錄

  缺省情況下,配置裝載的目錄如下:

數據庫類型

目錄

mysql

META-INF/druid/wall/mysql

oracle

META-INF/druid/wall/oracle

sqlserver

META-INF/druid/wall/sqlserver

postgres

META-INF/druid/wall/postgres

  從配置目錄中以下文件中讀取配置:

   deny-variant.txt deny-schema.txt deny-function.txt deny-table.txt deny-object.txt

  指定配置裝載的目錄是可以指定,例如:

<bean id="wall-filter-config" class="com.alibaba.druid.wall.WallConfig" init-method="init">      
    <!-- 指定配置裝載的目錄 -->
    <property name="dir" value="META-INF/druid/wall/mysql" />
</bean>
<bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">
    <property name="dbType" value="mysql" />
    <property name="config" ref="wall-filter-config" />
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    ...
    <property name="proxyFilters">
        <list>
            <ref bean="wall-filter"/>
        </list>
    </property>
</bean>

WallConfig詳細說明

本身的配置

配置項

缺省值

dir

按照dbType分別配置:
mysql : META-INF/druid/wall/mysql
oracle : META-INF/druid/wall/oracle
sqlserver : META-INF/druid/wall/sqlserver

攔截配置-語句

配置項

缺省值

描述

selelctAllow

true

是否允許執行SELECT語句

selectAllColumnAllow

true

是否允許執行SELECT * FROM T這樣的語句。如果設置為false,不允許執行select * from t,但select * from (select id, name from t) a。這個選項是防禦程序通過調用select *獲得數據表的結構信息。

selectIntoAllow

true

SELECT查詢中是否允許INTO字句

deleteAllow

true

是否允許執行DELETE語句

updateAllow

true

是否允許執行UPDATE語句

insertAllow

true

是否允許執行INSERT語句

replaceAllow

true

是否允許執行REPLACE語句

mergeAllow

true

是否允許執行MERGE語句,這個只在Oracle中有用

callAllow

true

是否允許通過jdbc的call語法調用存儲過程

setAllow

true

是否允許使用SET語法

truncateAllow

true

truncate語句是危險,缺省打開,若需要自行關閉

createTableAllow

true

是否允許創建表

alterTableAllow

true

是否允許執行Alter Table語句

dropTableAllow

true

是否允許修改表

commentAllow

false

是否允許語句中存在註釋,Oracle的用戶不用擔心,Wall能夠識別hints和註釋的區別

noneBaseStatementAllow

false

是否允許非以上基本語句的其他語句,缺省關閉,通過這個選項就能夠屏蔽DDL。

multiStatementAllow

false

是否允許一次執行多條語句,缺省關閉

useAllow

true

是否允許執行mysql的use語句,缺省打開

describeAllow

true

是否允許執行mysql的describe語句,缺省打開

showAllow

true

是否允許執行mysql的show語句,缺省打開

commitAllow

true

是否允許執行commit操作

rollbackAllow

true

是否允許執行roll back操作

如果把selectIntoAllow、deleteAllow、updateAllow、insertAllow、mergeAllow都設置為false,這就是一個只讀數據源了。

攔截配置-永真條件

配置項

缺省值

描述

selectWhereAlwayTrueCheck

true

檢查SELECT語句的WHERE子句是否是一個永真條件

selectHavingAlwayTrueCheck

true

檢查SELECT語句的HAVING子句是否是一個永真條件

deleteWhereAlwayTrueCheck

true

檢查DELETE語句的WHERE子句是否是一個永真條件

deleteWhereNoneCheck

false

檢查DELETE語句是否無where條件,這是有風險的,但不是SQL註入類型的風險

updateWhereAlayTrueCheck

true

檢查UPDATE語句的WHERE子句是否是一個永真條件

updateWhereNoneCheck

false

檢查UPDATE語句是否無where條件,這是有風險的,但不是SQL註入類型的風險

conditionAndAlwayTrueAllow

false

檢查查詢條件(WHERE/HAVING子句)中是否包含AND永真條件

conditionAndAlwayFalseAllow

false

檢查查詢條件(WHERE/HAVING子句)中是否包含AND永假條件

conditionLikeTrueAllow

true

檢查查詢條件(WHERE/HAVING子句)中是否包含LIKE永真條件

其他攔截配置

配置項

缺省值

描述

selectIntoOutfileAllow

false

SELECT ... INTO OUTFILE 是否允許,這個是mysql註入攻擊的常見手段,缺省是禁止的

selectUnionCheck

true

檢測SELECT UNION

selectMinusCheck

true

檢測SELECT MINUS

selectExceptCheck

true

檢測SELECT EXCEPT

selectIntersectCheck

true

檢測SELECT INTERSECT

mustParameterized

false

是否必須參數化,如果為True,則不允許類似WHERE ID = 1這種不參數化的SQL

strictSyntaxCheck

true

是否進行嚴格的語法檢測,Druid SQL Parser在某些場景不能覆蓋所有的SQL語法,出現解析SQL出錯,可以臨時把這個選項設置為false,同時把SQL反饋給Druid的開發者。

conditionOpXorAllow

false

查詢條件中是否允許有XOR條件。XOR不常用,很難判斷永真或者永假,缺省不允許。

conditionOpBitwseAllow

true

查詢條件中是否允許有"&"、"~"、"|"、"^"運算符。

conditionDoubleConstAllow

false

查詢條件中是否允許連續兩個常量運算表達式

minusAllow

true

是否允許SELECT * FROM A MINUS SELECT * FROM B這樣的語句

intersectAllow

true

是否允許SELECT * FROM A INTERSECT SELECT * FROM B這樣的語句

constArithmeticAllow

true

攔截常量運算的條件,比如說WHERE FID = 3 - 1,其中"3 - 1"是常量運算表達式。

limitZeroAllow

false

是否允許limit 0這樣的語句

禁用對象檢測配置

配置項

缺省值

描述

tableCheck

true

檢測是否使用了禁用的表

schemaCheck

true

檢測是否使用了禁用的Schema

functionCheck

true

檢測是否使用了禁用的函數

objectCheck

true

檢測是否使用了“禁用對對象”

variantCheck

true

檢測是否使用了“禁用的變量”

readOnlyTables

指定的表只讀,不能夠在SELECT INTO、DELETE、UPDATE、INSERT、MERGE中作為"被修改表"出現

Jdbc相關配置

配置項

缺省值

描述

metadataAllow

true

是否允許調用Connection.getMetadata方法,這個方法調用會暴露數據庫的表信息

wrapAllow

true

是否允許調用Connection/Statement/ResultSet的isWrapFor和unwrap方法,這兩個方法調用,使得有辦法拿到原生驅動的對象,繞過WallFilter的檢測直接執行SQL。

WallFiler配置說明

配置項

缺省值

描述

logViolation

false

對被認為是攻擊的SQL進行LOG.error輸出

throwException

true

對被認為是攻擊的SQL拋出SQLExcepton

config

provider

  剛開始引入WallFilter的時候,把logViolation設置為true,而throwException設置為false。就可以觀察是否存在違規的情況,同時不影響業務運行。

八、Druid參考

  不同的業務場景需求不同,你可以使用我們的參考配置,但建議你仔細閱讀相關文檔,了解清楚之後做定制配置。

  以下是一個參考的連接池配置:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">       
    
    <!-- 基本屬性 url、user、password -->
    <property name="url" value="${jdbc_url}" />
    <property name="username" value="${jdbc_user}" />
    <property name="password" value="${jdbc_password}" />

    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="1" />
    <property name="minIdle" value="1" />
    <property name="maxActive" value="20" />
    
  
    <!-- 配置獲取連接等待超時的時間 -->
    <property name="maxWait" value="60000" />
     
    <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="60000" />
    
    <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="300000" />

    <property name="validationQuery" value="SELECT ‘x‘" />
    <property name="testWhileIdle" value="true" />
    <property name="testOnBorrow" value="false" />
    <property name="testOnReturn" value="false" />
    
    <!-- 打開PSCache,並且指定每個連接上PSCache的大小 -->
    <property name="poolPreparedStatements" value="true" />
    <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />

    <!-- 配置監控統計攔截的filters -->
    <property name="filters" value="stat" />
</bean>

  通常來說,只需要修改initialSize、minIdle、maxActive。

  如果用Oracle,則把poolPreparedStatements配置為true,mysql可以配置為false。分庫分表較多的數據庫,建議配置為false。

十、Druid日誌

  Druid提供了Log4jFilter、CommonsLogFilter和Slf4jFilter,具體配置看這裏:

 Druid內置提供了三種LogFilter(Log4jFilter、CommonsLogFilter、Slf4jLogFilter),用於輸出JDBC執行的日誌。這些Filter都是Filter-Chain擴展機制中的Filter,所以配置方式可以參考這裏:Filter配置

  10.1、別名映射

  在druid-xxx.jar!/META-INF/druid-filter.properties文件中描述了這三種Filter的別名

druid.filters.log4j=com.alibaba.druid.filter.logging.Log4jFilter  
druid.filters.slf4j=com.alibaba.druid.filter.logging.Slf4jLogFilter
druid.filters.commonlogging=com.alibaba.druid.filter.logging.CommonsLogFilter
druid.filters.commonLogging=com.alibaba.druid.filter.logging.CommonsLogFilter

  他們的別名分別是log4j、slf4j、commonlogging和commonLogging。其中commonlogging和commonLogging只是大小寫不同。

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"      init-method="init" destroy-method="close">      
    ... ...
    <property name="filters" value="stat,log4j" />
</bean>

  10.2、loggerName映射

   LogFilter都是缺省使用四種不同的Logger執行輸出,看實現代碼:
public abstract class LogFilter {      
    protected String dataSourceLoggerName = "druid.sql.DataSource";
    protected String connectionLoggerName = "druid.sql.Connection";
    protected String statementLoggerName = "druid.sql.Statement";
    protected String resultSetLoggerName = "druid.sql.ResultSet";
}
  你可以根據你的需要修改,在log4j.properties文件上做配置時,註意配置使用相關的logger。 

  10.3、配置輸出日誌

  缺省輸入的日誌信息全面,但是內容比較多,有時候我們需要定制化配置日誌輸出。

<bean id="log-filter" class="com.alibaba.druid.filter.logging.Log4jFilter">    
    <property name="resultSetLogEnabled" value="false" />
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    ...
    <property name="proxyFilters">
      <list>
          <ref bean="log-filter"/>
      </list>
    </property>
</bean>

參數

說明

dataSourceLogEnabled

所有DataSource相關的日誌

connectionLogEnabled

所有連接相關的日誌

connectionLogErrorEnabled

所有連接上發生異常的日誌

statementLogEnabled

所有Statement相關的日誌

statementLogErrorEnabled

所有Statement發生異常的日誌

resultSetLogEnabled

resultSetLogErrorEnabled

connectionConnectBeforeLogEnabled

connectionConnectAfterLogEnabled

connectionCommitAfterLogEnabled

connectionRollbackAfterLogEnabled

connectionCloseAfterLogEnabled

statementCreateAfterLogEnabled

statementPrepareAfterLogEnabled

statementPrepareCallAfterLogEnabled

statementExecuteAfterLogEnabled

statementExecuteQueryAfterLogEnabled

statementExecuteUpdateAfterLogEnabled

statementExecuteBatchAfterLogEnabled

statementCloseAfterLogEnabled

statementParameterSetLogEnabled

resultSetNextAfterLogEnabled

resultSetOpenAfterLogEnabled

resultSetCloseAfterLogEnabled

  10.4、log4j.properties配置

  如果你使用log4j,可以通過log4j.properties文件配置日誌輸出選項,例如:

log4j.logger.druid.sql=warn,stdout  
log4j.logger.druid.sql.DataSource=warn,stdout
log4j.logger.druid.sql.Connection=warn,stdout
log4j.logger.druid.sql.Statement=warn,stdout
log4j.logger.druid.sql.ResultSet=warn,stdout

  10.5、輸出可執行的SQL

  Java啟動參數配置方式

-Ddruid.log.stmt.executableSql=true

  logFilter參數直接配置

<bean id="log-filter" class="com.alibaba.druid.filter.logging.Log4jFilter">        
    <property name="statementExecutableSqlLogEnable" value="true" />
</bean>

十一、Druid泄露

 Druid提供了多種監測連接泄漏的手段

  連接泄漏監測

 當程序存在缺陷時,申請的連接忘記關閉,這時候,就存在連接泄漏了。Druid提供了RemoveAbandanded相關配置,用來關閉長時間不使用的連接。例如:

  配置

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">    
    ... ...
    <property name="removeAbandoned" value="true" />
    <!-- 打開removeAbandoned功能 -->
    <property name="removeAbandonedTimeout" value="1800" />
    <!-- 1800秒,也就是30分鐘 -->
    <property name="logAbandoned" value="true" />
    <!-- 關閉abanded連接時輸出錯誤日誌 -->
    ... ...
</bean>

  配置removeAbandoned對性能會有一些影響,建議懷疑存在泄漏之後再打開。在上面的配置中,如果連接超過30分鐘未關閉,就會被強行回收,並且日誌記錄連接申請時的調用堆棧。

  內置監控頁面查看未關閉連接堆棧信息

 當removeAbandoned=true之後,可以在內置監控界面datasource.html中的查看ActiveConnection StackTrace屬性的,可以看到未關閉連接的具體堆棧信息,從而方便查出哪些連接泄漏了。

  web應用

 如果你的應用配置了WebStatFilter
 在內置監控頁面weburi-detail.html中,查看JdbcPoolConnectionOpenCount和JdbcPoolConnectionCloseCount屬性,如果不相等,就是泄漏了。

Druid連接池(二)