`
SoberChina
  • 浏览: 76742 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

数据连接池默认配置带来的坑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
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics