com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 0, maxActive20

记druid 连接池没满,但超时问题
异常信息:

com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 0, maxActive20

从这个异常信息的描述来看,跟常规的线程池满又不一样,通过异常信息来看,线程池没满(active<maxActive),但是获取连接超时,有点无头脑。

正常的应该差不多是这样:

com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 6000, active 100, maxActive 100

1、查询mysql配置

若最大连接数过小,满足不了业务需求,可修改mysql最大连接数

1、最大可连接数
show variables like 'max_connections';
2、运行中连接数       
show status like 'Threads_connected';

3、修改mysql最大连接数改为***
set GLOBAL max_connections = 6000; 

2、查询项目中连接池的配置

检查连接池中的最大连接数是否符合需求,若数值过小可调大数值。
下面是我自己注册的动态数据源的连接池配置。如果是一般的数据库连接,直接修改对应的配置项
如:spring.datasource.druid.max-active=100

    /**
     * 注册数据源
     * @param datacenterDb
     * @return
     */
    public static boolean registerDataSource(DatacenterDb datacenterDb) throws Throwable {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(datacenterDb.getDbUrl());
        druidDataSource.setDriverClassName(datacenterDb.getDbDriver());
        druidDataSource.setUsername(datacenterDb.getDbUsername());
        druidDataSource.setPassword(datacenterDb.getDbPassword().trim().toString());
        druidDataSource.setMaxActive(100); // 最大活动连接,连接池中可同时连接的最大的连接数(默认值为8)
        druidDataSource.setMaxWait(60000L); // 从池中取连接的最大等待时间,单位ms.当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常
        druidDataSource.setMinIdle(10); //最大空闲连接,连接池中最大的空闲的连接数,超过的空闲连接将被释放
        druidDataSource.setMaxCreateTaskCount(5);
        druidDataSource.setBreakAfterAcquireFailure(true);//尝试错误不再继续执行了(该参数不开启,只开启最大次数是不生效的)
        druidDataSource.setOnFatalErrorMaxActive(3);//设置尝试错误最大次数

        try {
            druidDataSource.init();
            dataSourcesMap.put(datacenterDb.getId(), druidDataSource);
        }catch (Throwable e){
            LOGGER.error("datacenterDbId:"+datacenterDb.getId()+"register failed");
            throw e;
        }
        return true;
    }

3、确认是否是提示性BUG

在一个个浏览github上相关问题时,突然发现某一个大神指出来,通过分析源码,该问题属于BUG,是一个提示性BUG。原因解释:
出现 GetConnectionTimeoutException 就是代表获取线程池超时,线程池满了。
为什么提示又说线程池没满呢( active 5, maxActive 100 )?
这是因为异常的日志打印没有放在同步块中,使用的变量没有考虑多线程。
简单说就是,在打印日志时,变量(active)的值已被修改,所以不是异常发生时的值。
代码大概如下: DruidDataSource - 1394

            if (holder == null) {
            long waitNanos = waitNanosLocal.get();
 
            StringBuilder buf = new StringBuilder();
            buf.append("wait millis ")//
               .append(waitNanos / (1000 * 1000))//
               .append(", active ").append(activeCount)//
               .append(", maxActive ").append(maxActive)//
               .append(", creating ").append(creatingCount.get())//

问题重现

  1. 在查询时特意的将时间延长,造成连接池被占用
  2. 在异常打印日志之前增加一点延迟(比如打个断点)

结论
本身就是因为服务中出现了一些比较复杂耗时的SQL,导致长时间占用了连接。
但是druid打印le 会产生歧义的异常,误导了问题分析的方向,增加了复杂度。

当前使用的druid版本是1.1.5, 1.2.16后bug才修复,使用1.2.16之后的版本

        <!--数据源,数据库连接池-->
        <!-- 实现对 Druid 连接池的自动化配置 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.21</version>
        </dependency>

原文链接:https://blog.csdn.net/xiaolaoban212/article/details/115357734

MYSQL配置详解

initialSize=“10” :初始化连接,连接池启动时创建的初始化连接数量(默认值为0)

maxActive=“80” :最大活动连接,连接池中可同时连接的最大的连接数(默认值为8)

minIdle=“10” : 最小空闲连接,连接池中最小的空闲的连接数,低于这个数量会被创建新的连接(默认为0,该参数越接近maxIdle,性能越好,因为连接的创建和销毁,都是需要消耗资源的;但是不能太大,因为在机器很空闲的时候,也会创建低于minidle个数的连接,类似于jvm参数中的Xmn设置)

maxIdle=“60” : 最大空闲连接,连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制(默认为8个,maxIdle不能设置太小,因为假如在高负载的情况下,连接的打开时间比关闭的时间快,会引起连接池中idle的个数上升超过maxIdle,而造成频繁的连接销毁和创建,类似于jvm参数中的Xmx设置)

maxWait=“3000” : 从池中取连接的最大等待时间,单位ms.当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待(默认为无限)

validationQuery = “SELECT 1” : 验证使用的SQL语句

testWhileIdle = “true” :指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.

testOnBorrow = “false” : 借出连接时不要测试,否则很影响性能。一定要配置,因为它的默认值是true。false表示每次从连接池中取出连接时,不需要执行validationQuery = “SELECT 1” 中的SQL进行测试。若配置为true,对性能有非常大的影响,性能会下降7-10倍。

timeBetweenEvictionRunsMillis = “30000” : 每30秒运行一次空闲连接回收器,配置timeBetweenEvictionRunsMillis = "30000"后,每30秒运行一次空闲连接回收器(独立线程)。并每次检查3个连接,如果连接空闲时间超过30分钟就销毁。销毁连接后,连接数量就少了,如果小于minIdle数量,就新建连接,维护数量不少于minIdle,过行了新老更替。

minEvictableIdleTimeMillis = “1800000” : 池中的连接空闲30分钟后被回收

numTestsPerEvictionRun=“3” : 在每次空闲连接回收器线程(如果有)运行时检查的连接数量

removeAbandoned=“true” : 连接泄漏回收参数,当可用连接数少于3个时才执行

removeAbandonedTimeout=“180” : 连接泄漏回收参数,180秒,泄露的连接可以被删除的超时值

注意事项
maxIdle值与maxActive值应配置的接近
当连接数超过maxIdle值后,刚刚使用完的连接(刚刚空闲下来)会立即被销毁。而不是想要的空闲M秒后再销毁起一个缓冲作用。若maxIdle与maxActive相差较大,在高负载的系统中会导致频繁的创建、销毁连接,连接数在maxIdle与maxActive间快速频繁波动,这不是想要的。高负载系统的maxIdle值可以设置为与maxActive相同或设置为-1(-1表示不限制),让连接数量在minIdle与maxIdle间缓冲慢速波动。

timeBetweenEvictionRunsMillis建议设置值
minIdle要与timeBetweenEvictionRunsMillis配合使用才有用,单独使用minIdle不会起作用。

initialSize=“5”,会在tomcat一启动时,创建5条连接,效果很理想。但同时我们还配置了minIdle=“10”,也就是说,最少要保持10条连接,那现在只有5条连接,哪什么时候再创建少的5条连接呢?
1、等业务压力上来了, DBCP就会创建新的连接。
2、配置timeBetweenEvictionRunsMillis=“时间”,DBCP会启用独立的工作线程定时检查,补上少的5条连接。销毁多余的连接也是同理。

连接销毁的逻辑

DBCP的连接数会在initialSize - minIdle - maxIdle - maxActive 之间变化。变化的逻辑描述如下:
默认未配置initialSize(默认值是0)和timeBetweenEvictionRunsMillis参数时,刚启动tomcat时,连接数是0。当应用有一个并发访问数据库时DBCP创建一个连接。目前连接数量还未达到minIdle,但DBCP也不自动创建新连接已使数量达到minIdle数量(没有一个独立的工作线程来检查和创建)。随着应用并发访问数据库的增多,连接数也增多,但都与minIdle值无关,很快minIdle被超越,minIdle值一点用都没有。直到连接的数量达到maxIdle值,这时的连接都是只增不减的。 再继续发展,连接数再增多并超过maxIdle时,使用完的连接(刚刚空闲下来的)会立即关闭,总体连接的数量稳定在maxIdle但不会超过maxIdle。
但活动连接(在使用中的连接)可能数量上瞬间超过maxIdle,但永远不会超过maxActive。这时如果应用业务压力小了,访问数据库的并发少了,连接数也不会减少(没有一个独立的线程来检查和销毁),将保持在maxIdle的数量。

默认未配置initialSize(默认值是0),但配置了timeBetweenEvictionRunsMillis=“30000”(30秒)参数时,刚启动tomcat时,连接数是0。马上应用有一个并发访问数据库时DBCP创建一个连接。目前连接数量还未达到minIdle,每30秒DBCP的工作线程检查连接数是否少于minIdle数量,若少于就创建新连接直到达到minIdle数量。
随着应用并发访问数据库的增多,连接数也增多,直到达到maxIdle值。这期间每30秒DBCP的工作线程检查连接是否空闲了30分钟,若是就销毁。但此时是业务的高峰期,是不会有长达30分钟的空闲连接的,工作线程查了也是白查,但它在工作。到这里连接数量一直是呈现增长的趋势。
当连接数再增多超过maxIdle时,使用完的连接(刚刚空闲下来)会立即关闭,总体连接的数量稳定在maxIdle。停止了增长的趋势。但活动连接(在使用中的连接)可能数量上瞬间超过maxIdle,但永远不会超过maxActive。
这时如果应用业务压力小了,访问数据库的并发少了,每30秒DBCP的工作线程检查连接(默认每次查3条)是否空闲达到30分钟(这是默认值),若连接空闲达到30分钟,就销毁连接。这时连接数减少了,呈下降趋势,将从maxIdle走向minIdle。当小于minIdle值时,则DBCP创建新连接已使数量稳定在minIdle,并进行着新老更替。

MYSQL常用配置参考:

DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername(username);
        druidDataSource.setUrl(url);
        druidDataSource.setPassword(password);
        druidDataSource.setDriverClassName(className);
        druidDataSource.setInitialSize(20);
        druidDataSource.setMaxActive(80);
        druidDataSource.setMinIdle(20);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setValidationQuery("SELECT 1");
        druidDataSource.setMinEvictableIdleTimeMillis(1800000);
        druidDataSource.setRemoveAbandoned(true);
        druidDataSource.setRemoveAbandonedTimeout(1800);
        druidDataSource.setFilters("stat,wall,slf4j,config");
        druidDataSource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");
        druidDataSource.setUseGlobalDataSourceStat(true);

原文链接:https://blog.csdn.net/qq_38971617/article/details/116758538

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
com.alibaba.druid.pool.GetConnectionTimeoutException是阿里巴巴Druid数据库连接池的数据库获取连接超时异常。具体来说,错误信息中的active 20表示当前活动的连接数为20maxActive 20表示最大连接数为20,creating 0表示当前正在创建的连接数为0。这个异常的出现是因为在等待新的连接时,连接池中没有可用的连接,导致超时。 要解决这个问题,有几个可能的解决方案。首先,可以增加连接池的最大连接数,以便更多的连接可以同时被使用。其次,可以检查代码中是否有未关闭的连接,如果有,及时关闭这些连接以释放资源。此外,还可以调整连接超时时间,根据实际情况增加等待新连接的时间。最后,可以考虑使用连接池的监控工具来查看连接的使用情况,并根据监控结果进行优化。 综上所述,解决com.alibaba.druid.pool.GetConnectionTimeoutException异常的方法包括增加连接池的最大连接数、检查未关闭的连接、调整连接超时时间和使用连接池的监控工具进行优化。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 20, maxActive 20 ...](https://blog.csdn.net/shenshuiqiutong/article/details/131668509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 20, maxActive 20](https://blog.csdn.net/waysoflife/article/details/126417672)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值