欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了

程序员文章站 2022-05-12 17:08:57
...

首先说一下自己程序中遇到的问题,前一段新写了一个项目,主要为方便公司业务切库做准备,为其他项目提供接口(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状态下,需要完成的事情是等待你去关闭连接。


数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false

看了一下不会出现中途死掉的问题,作为服务端关闭处理应该在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 如图:


数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false

spring boot 集成mybatis 默认使用 jdbc连接池

org.apache.tomcat.jdbc.pool默认testOnBorrow=false 


数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false
 

但是在 spring boot 集成mybatis时候 却默认修改了配置如图:


数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false
 

这篇文章解释的挺不错

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中游历不被计算为被使用.

  • 数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false
  • 大小: 51.7 KB
  • 数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false
  • 大小: 248.2 KB
  • 数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false
  • 大小: 109.5 KB
  • 数据连接池默认配置带来的坑testOnBorrow=false,cloes_wait 终于解决了
            
    
    博客分类: javadruid javaclose_wait连接池testOnBorrow=false
  • 大小: 123.8 KB