开发者社区> 山那边风景> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

排查数据库连接池错误

简介: 最近在使用druid数据源时,碰到一个问题closed connection。在本地及测试环境都运行正常,但是在正式环境,过一段时间就出现closed conneciton问题,关闭的连接。
+关注继续查看

一、closed connection

最近有个需求,单线程监控kafka数据的变化,再由简单的逻辑查询数据库,封装查询接口,使用open-feign调用接口。具体链路如下图所示:

image

因kafka的数据变化较快,需要频繁查询数据库,所以使用了druid的数据源。程序在测试环境执行没有任何问题,一旦在生产环境上执行就会出现closed connection错误,经过排查分析原因,发现oralce数据库超过一定的时间会把链接断开,当数据源再去使用连接时就会报closed connect错误。

详细分析配置文件中,发现其中几个配置有问题,详细分析以下几个配置

maxActive
最大连接池数量,允许的最大同时使用中的连接数。这里特地唠叨一下,配置 maxActive 千万不要好大喜多,虽然配置大了看起来业务流量飙升后还能处理更多的请求,但切换到 DB 视角会发现其实连接数的增多在很多场景下反而会减低吞吐量,一个非常典型的例子就秒杀,在更新热点数据时 DB 需要加锁操作,这个时候再让更多的连接操作 DB 就有点像假日往高速上涌入的车辆,只会给 DB 添堵。

keepAlive
参数表示是否对空闲连接保活,布尔类型。可能不少人认为 druid 连接池默认会维持DB连接的心跳,对池子中的连接进行保活,特别配置了 minIdle 这个参数后觉得,有了 minIdle 最少应该会保持这么多空闲连接。其实,keepAlive 这个参数是在 druid 1.0.28 后新增的,并且默认值是 false,即不进行连接保活。

那么需要保活连接,是不是将 keepAlive 配置成 true 就完事了呢?虽然 true 的确是开启了保活机制,但是应该保活多少个,心跳检查的规则是什么,这些都需要正确配置,否则还是可能事与愿违。这里需要了解几个相关的参数:minIdle 最小连接池数量,连接保活的数量,空闲连接超时踢除过程会保留的连接数(前提是当前连接数大于等于 minIdle),其实 keepAlive 也仅维护已存在的连接,而不会去新建连接,即使连接数小于 minIdle;minEvictableIdleTimeMillis 单位毫秒,连接保持空闲而不被驱逐的最小时间,保活心跳只对存活时间超过这个值的连接进行;maxEvictableIdleTimeMillis 单位毫秒,连接保持空闲的最长时间,如果连接执行过任何操作后计时器就会被重置(包括心跳保活动作);timeBetweenEvictionRunsMillis 单位毫秒,Destroy 线程检测连接的间隔时间,会在检测过程中触发心跳。保活检查的详细流程可参见源码com.alibaba.druid.pool.DruidDataSource.DestroyTask,其中心跳检查会根据配置使用 ping 或 validationQuery 配置的检查语句。

maxEvictableIdleTimeMillis 和 minEvictableIdleTimeMillis

/**

DestroyTask 线程销毁任务每隔 timeBetweenEvictionRunsMillis

(默认一分钟)的时间会执行一次连接池瘦身检测

**/

if (idleMillis >= minEvictableIdleTimeMillis) {

    if (checkTime && i < checkCount) {  // checkCount = poolingCount - minIdle

        evictConnections[evictCount++] = connection;

        continue;

    } else if (idleMillis > maxEvictableIdleTimeMillis) {

        evictConnections[evictCount++] = connection;

        continue;

    }

}

checkTime = true 所以会再判断 i < checkCount 是否成立,而 checkCount = poolingCount - minIdle 也就是超过 minIdle 那部分连接(类似线程池的 maximumPoolSize - corePoolSize )

所以,代码逻辑是 1~minIdle 的连接空闲超过 maxEvictableIdleTimeMillis(默认7小时) 则需要清除掉, minEvictableIdleTimeMillis(默认30分钟) 针对的是超过 minIdle 的那部分连接

maxEvictableIdleTimeMillis 表示的是 minIdle 内连接能空闲的最大时长。

因为程序启动时间在中午11:30分左右,这就是为什么程序是在凌晨1:30分左右报错的原因,因配置文件没有配置maxEvictableIdleTimeMillis此参数,默认7个小时,druid要关闭超过最大空闲时间的连接,关闭连接连接时(oracle客户端已经把连接关闭),所以日志报错closed connection。

二、解决办法

1、因为程序是单线程,所以调整了minActive 和minIdle ,把参数值都调整为1,尽量不保留空闲连接,没有空闲连接,就不会关闭连接,就不会报错。

2、开启keep-alive参数设置为true,查看数据库配置的关闭空闲连接的时间,修改maxEvictableIdleTimeMillis的默认值(单位为ms),小于数据库配置的默认时间。select resource_name,resource_type,limit from dba_profiles where profile='DEFAULT' ;

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
连接并使用数据库
连接并使用数据库
14 0
数据库的连接代码
数据库的连接代码
37 0
云数据库的连接
大家好,小编整理了关于如何简单登录阿里云数据库的步骤,请看官参考
2109 0
数据库连接详解
这篇文章是基于我开发读写分离中间件和数据库智能运维平台时的经验总结而成。网上对数据库连接系统分析的文章非常少,甚至几乎没有。这篇文章很多内容都参杂了我个人的见解,不一定全,但是每一个知识点都是我验证过的。
1310 0
day13_Mysql事务与数据库连接池学习笔记
day13_Mysql事务与数据库连接池学习笔记 一、Mysql的事务    事务: 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功(数据回滚)。
1792 0
后台(20)——数据库连接池
探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分...
1249 0
+关注
山那边风景
系统架构师,热爱生活,喜欢健身、跑步,持续学习,持续精进
62
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载