数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
首先說一下自己程序中遇到的問題,前一段新寫了一個項目,主要為方便公司業務切庫做準備,為其他項目提供接口(spring boot 項目<spring boot + mongo data jpa+mybatis>) 首先呢 多數據源沒有使用spring boot 集成mybatis,開始有過自己搭建spring boot 都是單數據源的,所以沒有自己手寫加載數據源的代碼(比較懶),在新項目中使用的是阿里的druid連接池,配置當然更簡單了,除了數據庫地址,驅動類,用戶名和密碼其他一起都是默認,開始的時候由于項目更新上線頻率比較多,沒有出現太多的問題,而且訪問比較頻繁,接著慢慢提供接口,后來上線了一個 訪問頻率不大的接口,那么問題就出現了,隔了一段時間,某一臺服務器掛了,服務器 netstat -ant | wc -l ?六七千,netstat -ant | tail ?鏈接出現大量的close_wait ,很是頭疼,開始從tcp下手找問題,這種狀態的含義其實是表示在等待關閉。怎么理解呢?當對方close一個SOCKET后發送FIN報文給自己,你系統毫無疑問地會回應一個ACK報文給對 方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有數據發送給對方,如果沒有的話,那么你也就可以 close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。
看了一下不會出現中途死掉的問題,作為服務端關閉處理應該在tomcat上,spring Boot 內嵌的tomcat不可能這么弱,后來查了一下dump 發現線程卡在
sun.misc.Unsafe.park(Unsafe.java:-2) native
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:1521)
com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1146)
?這時候開始考慮數據庫連接池的問題?,跟了一下代碼以及其他項目的配置,其中有一個屬性 testOnBorrow設置為false(默認設置為false) testOnBorrow=false由于不檢測池里連接的可用性,
?
于是假如連接池中的連接被數據庫關閉了,應用通過連接池getConnection時,都可能獲取到這些不可
用的連接,且這些連接如果不被其他線程回收的話,它們不會被連接池被廢除,也不會重新被創建,
占用了連接池的名額,項目本身作為服務端,數據庫鏈接被關閉,客戶端調用服務端就會出現大量的timeout,客戶端設置了超時時間,然而主動斷開,服務端必然出現close_wait。spring Boot 內嵌的tomcat 默認最大線程數是200,很快就掛掉,雖說多數源,沒有問題的數據源,鏈接并發過來也會死掉,所以說加大tomcat 默認線程(server.tomcat.max-threads=3000)只是短時間內其他數據源鏈接不會死掉,現在對比一下連接池 druid 如圖:
spring boot 集成mybatis 默認使用 jdbc連接池
org.apache.tomcat.jdbc.pool默認testOnBorrow=false?
?
但是在?spring boot 集成mybatis時候 卻默認修改了配置如圖:
?
這篇文章解釋的挺不錯
http://blog.csdn.net/wangyangzhizhou/article/details/52209336
默認的配置不適用所有場景,需要注意一下。
?但是這個鍋不能丟給druid,testOnborrow =true 很大的消耗性能,從而保證服務器的穩定,可以配合其他配置來避免這一點,配合testWhileIdle=true(但是默認為false) 和timeBetweenEvictionRunsMillis來避免這種問題,這么重要的幾個配置,為什么都要默認為false呢,為了提高效率,從而導致服務器很大的潛在問題?自認為有點兒得不償失,(最起碼默認一種折中的配置感覺比較好)。
下面的注釋為轉來的。很詳細
?
?
?
tomcatde DHCP的配置
<Resource driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"?
logAbandoned="true" maxActive="20" maxIdle="2" maxWait="5000" name="system"?
removeAbandonedTimeout="60" removeAbandoned="true"?
password="xx" type="javax.sql.DataSource"
url="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=base"?
username="sa"/>
當中的
logAbandoned="true" ?removeAbandoned="true" removeAbandonedTimeout="60"
就是用來配置數據庫斷開后自動連接的。
?
?
數據庫連接池會在啟動時就建立所需的若干連接,并一直保持連接狀態,
但是當數據庫服務停止后,這些連接就被外部因素給中斷了
網上優化了的配置信息:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> ?
<property name="driverClassName" value="${db.driverClassName}"/> ?
<property name="url" value="${db.url}"/> ?
<property name="username" value="${db.username}"/> ?
<property name="password" value="${db.password}"/> ?
<!--initialSize: 初始化連接--> ?
<property name="initialSize" value="5"/> ?
<!--maxIdle: 最大空閑連接--> ?
<property name="maxIdle" value="10"/> ?
<!--minIdle: 最小空閑連接--> ?
<property name="minIdle" value="5"/> ?
<!--maxActive: 最大連接數量--> ?
<property name="maxActive" value="15"/> ?
<!--removeAbandoned: 是否自動回收超時連接--> ?
<property name="removeAbandoned" value="true"/> ?
<!--removeAbandonedTimeout: 超時時間(以秒數為單位)--> ?
<property name="removeAbandonedTimeout" value="180"/> ?
<!--maxWait: 超時等待時間以毫秒為單位 6000毫秒/1000等于60秒--> ?
<property name="maxWait" value="3000"/> ?
<property name="validationQuery"> ?
<value>SELECT 1</value> ?
</property> ?
<property name="testOnBorrow"> ?
<value>true</value> ?
</property> ?
</bean> ?
?
dbcp配置中文版本,自apache 官方文檔
原文請見http://commons.apache.org/dbcp/configuration.html。
?
參數 ?描述
username ?傳遞給JDBC驅動的用于建立連接的用戶名
password ?傳遞給JDBC驅動的用于建立連接的密碼
url ?傳遞給JDBC驅動的用于建立連接的URL
driverClassName ?使用的JDBC驅動的完整有效的java 類名
connectionProperties ?當建立新連接時被發送給JDBC驅動的連接參數,
格式必須是 [propertyName=property;]*
注意 :參數user/password將被明確傳遞,所以不需要包括在這里。
?
參數 ?默認值 ?描述
defaultAutoCommit ?true ?連接池創建的連接的默認的auto-commit狀態
defaultReadOnly ?driver default ?連接池創建的連接的默認的read-only狀態.?
如果沒有設置則setReadOnly方法將不會被調用. (某些驅動不支持只讀模式,比如:Informix)
defaultTransactionIsolation ?driver default ?連接池創建的連接的默認的TransactionIsolation狀態.?
下面列表當中的某一個: (參考javadoc)
?
? ? * NONE
? ? * READ_COMMITTED
? ? * READ_UNCOMMITTED
? ? * REPEATABLE_READ
? ? * SERIALIZABLE
?
defaultCatalog ? 連接池創建的連接的默認的catalog
?
參數 ?默認值 ?描述
initialSize ?0 ?初始化連接:連接池啟動時創建的初始化連接數量,1.2版本后支持
maxActive ?8 ?最大活動連接:連接池在同一時間能夠分配的最大活動連接的數量,?
如果設置為非正數則表示不限制
maxIdle ?8 ?最大空閑連接:連接池中容許保持空閑狀態的最大連接數量,超過的空閑連接將被釋放,
如果設置為負數表示不限制
minIdle ?0 ?最小空閑連接:連接池中容許保持空閑狀態的最小連接數量,低于這個數量將創建新的連接,
如果設置為0則不創建
maxWait ?無限 ?最大等待時間:當沒有可用連接時,連接池等待連接被歸還的最大時間(以毫秒計數),
超過時間則拋出異常,如果設置為-1表示無限等待
?
參數 ?默認值 ?描述
validationQuery ? SQL查詢,用來驗證從連接池取出的連接,在將連接返回給調用者之前.如果指定,
則查詢必須是一個SQL SELECT并且必須返回至少一行記錄
testOnBorrow ?true ?指明是否在從池中取出連接前進行檢驗,如果檢驗失敗,
則從池中去除連接并嘗試取出另一個.
注意: 設置為true后如果要生效,validationQuery參數必須設置為非空字符串
testOnReturn ?false ?指明是否在歸還到池中前進行檢驗
注意: 設置為true后如果要生效,validationQuery參數必須設置為非空字符串
testWhileIdle ?false ?指明連接是否被空閑連接回收器(如果有)進行檢驗.如果檢測失敗,
則連接將被從池中去除.
注意: 設置為true后如果要生效,validationQuery參數必須設置為非空字符串
timeBetweenEvictionRunsMillis ?-1 ?在空閑連接回收器線程運行期間休眠的時間值,以毫秒為單位.
?如果設置為非正數,則不運行空閑連接回收器線程
numTestsPerEvictionRun ?3 ?在每次空閑連接回收器線程(如果有)運行時檢查的連接數量
minEvictableIdleTimeMillis ?1000 * 60 * 30 ?連接在池中保持空閑而不被空閑連接回收器線程
(如果有)回收的最小時間值,單位毫秒
?
參數 ?默認值 ?描述
poolPreparedStatements ?false ?開啟池的prepared statement 池功能
maxOpenPreparedStatements ?不限制 ?statement池能夠同時分配的打開的statements的最大數量,?
如果設置為0表示不限制
?
?
這里可以開啟PreparedStatements池. 當開啟時, 將為每個連接創建一個statement池,
并且被下面方法創建的PreparedStatements將被緩存起來:
? ? * public PreparedStatement prepareStatement(String sql)
? ? * public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
注意: 確認連接還有剩余資源可以留給其他statement
參數 ?默認值 ?描述
accessToUnderlyingConnectionAllowed ?false ?控制PoolGuard是否容許獲取底層連接
?
?
如果容許則可以使用下面的方式來獲取底層連接:
? ? Connection conn = ds.getConnection();
? ? Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate();
? ? ...
? ? conn.close();
?
默認false不開啟, 這是一個有潛在危險的功能, 不適當的編碼會造成傷害.
(關閉底層連接或者在守護連接已經關閉的情況下繼續使用它).請謹慎使用,
并且僅當需要直接訪問驅動的特定功能時使用.
注意: 不要關閉底層連接, 只能關閉前面的那個.
參數 ?默認值 ?描述
removeAbandoned ?false ?標記是否刪除泄露的連接,如果他們超過了removeAbandonedTimout的限制.
如果設置為true, 連接被認為是被泄露并且可以被刪除,如果空閑時間超過removeAbandonedTimeout.?
設置為true可以為寫法糟糕的沒有關閉連接的程序修復數據庫連接.
removeAbandonedTimeout ?300 ?泄露的連接可以被刪除的超時值, 單位秒
logAbandoned ?false ?標記當Statement或連接被泄露時是否打印程序的stack traces日志。
被泄露的Statements和連接的日志添加在每個連接打開或者生成新的Statement,
因為需要生成stack trace。
?
?
如果開啟"removeAbandoned",那么連接在被認為泄露時可能被池回收. 這個機制在(getNumIdle() < 2)
?and (getNumActive() > getMaxActive() - 3)時被觸發.
舉例當maxActive=20, 活動連接為18,空閑連接為1時可以觸發"removeAbandoned".
但是活動連接只有在沒有被使用的時間超過"removeAbandonedTimeout"時才被刪除,默認300秒.
在resultset中游歷不被計算為被使用.
- 大小: 51.7 KB
- 大小: 248.2 KB
- 大小: 109.5 KB
- 大小: 123.8 KB
- 查看圖片附件
總結
以上是生活随笔為你收集整理的数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习numpy快速入门教程 心得体会(1
- 下一篇: 路由策略实验