abandon connection问题分析
问题
- 出现
abandon connection, owner thread: http-nio-80-exec-19, connected at : 1610323631944, open stackTrace.....
错误日志信息 - 出现异常
nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60004, active 60, maxActive 60, creating 0] with root cause
流程
1. 项目启动时,利用springboot自动装配的原理会加载阿里数据源配置类DruidDataSourceAutoConfigure
public class DruidDataSourceAutoConfigure {private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);@Bean(initMethod = "init")@ConditionalOnMissingBeanpublic DataSource dataSource() {LOGGER.info("Init DruidDataSource");return new DruidDataSourceWrapper();}
}
DruidDataSourceWrapper
继承了DruidDataSource
。由于指定了initMethod = “init”,所以spring在创建DruidDataSourceWrapper
对象时,会执行DruidDataSource
的init
方法。
2. init()初始化
2.1 设置连接池的最大容量
private volatile DruidConnectionHolder[] connections;
.......connections = new DruidConnectionHolder[maxActive];
2.2 init()内的createAndStartCreatorThread()方法
会开一个线程,用来创建连接,并放入DruidConnectionHolder[]中,但线程一开始进入会被阻塞,知道有获取连接的方法执行,再将其唤醒。
2.3 init()内的createAndStartDestroyThread()方法
会开一个定时线程池定时执行扫描。
protected void createAndStartDestroyThread() {destroyTask = new DestroyTask();if (destroyScheduler != null) {long period = timeBetweenEvictionRunsMillis;if (period <= 0) {period = 1000;}destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period,TimeUnit.MILLISECONDS);initedLatch.countDown();return;}String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);destroyConnectionThread = new DestroyConnectionThread(threadName);destroyConnectionThread.start();
}
public class DestroyTask implements Runnable {@Overridepublic void run() {shrink(true, keepAlive);if (isRemoveAbandoned()) {removeAbandoned();}}}
当配置了removeAbandoned = true,if条件会进入执行removeAbandoned()。
public int removeAbandoned() {int removeCount = 0;long currrentNanos = System.nanoTime();List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();activeConnectionLock.lock();try {Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();for (; iter.hasNext();) {DruidPooledConnection pooledConnection = iter.next();if (pooledConnection.isRunning()) {continue;}long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);if (timeMillis >= removeAbandonedTimeoutMillis) {iter.remove();pooledConnection.setTraceEnable(false);abandonedList.add(pooledConnection);}}} finally {activeConnectionLock.unlock();}if (abandonedList.size() > 0) {for (DruidPooledConnection pooledConnection : abandonedList) {final ReentrantLock lock = pooledConnection.lock;lock.lock();try {if (pooledConnection.isDisable()) {continue;}} finally {lock.unlock();}JdbcUtils.close(pooledConnection);pooledConnection.abandond();removeAbandonedCount++;removeCount++;if (isLogAbandoned()) {StringBuilder buf = new StringBuilder();buf.append("abandon connection, owner thread: ");buf.append(pooledConnection.getOwnerThread().getName());buf.append(", connected at : ");buf.append(pooledConnection.getConnectedTimeMillis());buf.append(", open stackTrace\n");StackTraceElement[] trace = pooledConnection.getConnectStackTrace();for (int i = 0; i < trace.length; i++) {buf.append("\tat ");buf.append(trace[i].toString());buf.append("\n");}buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState()+ ", current stackTrace\n");trace = pooledConnection.getOwnerThread().getStackTrace();for (int i = 0; i < trace.length; i++) {buf.append("\tat ");buf.append(trace[i].toString());buf.append("\n");}LOG.error(buf.toString());}}}return removeCount;
}
可以分析出init()执行后,会有个定时线程池每秒执行一次任务,这个任务逻辑是获取活跃连接,判断目前的时间和当时获取连接时的时间相减是否超过了removeAbandonedTimeout配置的时间。超过的话将这个连接从活跃连接中删掉,并加入废弃连接的集合中
,如果配置了logAbandoned为true,则打印错误日志:abandon connection, owner thread:…
3. 获取连接
service
添加默认事务后,controller
调用service
方法时,会执行spring
的代理方法在开启事务时获取数据源的连接。
DataSourceTransactionManager
:
Connection newCon = this.dataSource.getConnection();
这里的dataSource
实际为DruidDataSource
getConnection() -> getConnectionInternal()
pollLast(long nanos)
- 如果连接池数量poolingCount为0,也就是没有池中没有连接,则:
执行emptySignal() 将之前init()方法中的createAndStartCreatorThread()创建的创建线程任务从被阻塞转为唤醒,创建连接连接,放入DruidConnectionHolder[]数组中(前提是不要超过maxActive数量)
。 - 如果连接池数量poolingCount仍然后为0,则直接返回null。
- 检查从pollLast(long nanos)获取的连接,如果为空,则抛出异常。
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)//;List<JdbcSqlStatValue> sqlList = this.getDataSourceStat().getRuningSqlList();for (int i = 0; i < sqlList.size(); ++i) {if (i != 0) {buf.append('\n');} else {buf.append(", ");}JdbcSqlStatValue sql = sqlList.get(i);buf.append("runningSqlCount ").append(sql.getRunningCount());buf.append(" : ");buf.append(sql.getSql());}String errorMessage = buf.toString();if (this.createError != null) {throw new GetConnectionTimeoutException(errorMessage, createError);} else {throw new GetConnectionTimeoutException(errorMessage);}
}
解决方案
由以上分析可知,是获取连接执行时间过长导致的。所以在执行时间较长不需要回滚的情况下,使用Propagation.PROPAGATION_NOT_SUPPORTED
不使用事务的传播行为配置
注意
- 要在从controller控制层调用的service方法上使用
@Transactional
注解,因为事务原理是用aop动态代理。
abandon connection问题分析相关推荐
- Druid连接池 报错:abandon connection原因分析
问题现象: 使用Druid的数据库连接池,在进行一个查询SQL的时候,抛出了异常: [2017-10-20 01:40:59.269 ERROR com.alibaba.druid.pool.Drui ...
- com.alibaba.druid.pool.DruidDataSource - abandon connection, open stackTrace
错误: com.alibaba.druid.pool.DruidDataSource - abandon connection, open stackTrace 原因: 连接池为了防止程序从池里取得连 ...
- abandon connection, owner thread: xxxx, connected at : 1606897800625, open stackTrace
问题现象: 使用Druid的数据库连接池,在进行一个查询SQL的时候,抛出了异常: [2017-10-20 01:40:59.269 ERROR com.alibaba.druid.pool.Drui ...
- Druid连接池一个设置引发的血案【abandon connection, open stackTrace】
2019独角兽企业重金招聘Python工程师标准>>> 今天在一台配置很低的机器上运行批量更新的程序~~~ 大概跑了三十分钟~~~这配置~~~这程序~~~ 然后华丽丽的报异常了~~~ ...
- ERROR com.alibaba.druid.pool.DruidDataSource - abandon connection, open stackTrace: 已解决
错误日志: 2020-07-13 15:37:58,545 [Druid-ConnectionPool-Destroy-2092318840] ERROR com.alibaba.druid.pool ...
- abandon connection报错连接池问题
abandon connection 报错来自于DruidDataSource这个类,根据报错的信息,可以看出是因为执行SQL时获取不到Connection连接,然后去看一下Druid的配置中,有三个 ...
- mysql no connections_mysql数据库NO CONNECTION问题分析以及解决方案
自己的站点有时候会挂掉,着实比较麻烦,我不会24小时都看着,说多的都是泪 出现mysql出现NO CONNECTION 有可能原因:mysql服务出现问题 解决方案:重启mysql服务,数据库就连接上 ...
- RabbitMQ connection.CreateModel() 分析
- connection holder is null
1 连接被回收 (1)错误日志 Caused by: java.sql.SQLException: connection holder is null at com.alibaba.druid.poo ...
- 瞬发大量并发连接 造成MySQL连接不响应的分析
http://www.actionsky.com/docs/archives/252 2016年12月7日 黄炎 目录 1 现象 2 猜想 3 检查环境 4 猜想2 5 分析 5.1 TCP握手的 ...
最新文章
- 【组队学习】【33期】动手学数据分析
- 【SpringCloud】Zuul-实例
- python爬虫用urllib还是reques,python爬虫中urllib.request和requests有什么区别?
- python初学工资-python工资高还是java?
- Django资源大全
- 传递参数命令——xargs
- go get github.com/astaxie/beego 没有反应
- 使用 CSS 用户选择控制选择
- IE8,9下的ajax缓存问题
- Spring注解实现aop
- 【运输量预测】基于matlab多种算法公路运输量预测【含Matlab源码 041期】
- api 文件长度_上传下载API
- docker学习笔记3:镜像操作(查找和下载)
- 高质量程序设计指南C++/C试题
- uiso9|uiso9_cn.exe
- PCWorld:HTML5会终结移动应用程序吗?
- 网易博客搬家至CSDN博客指南
- 中国通信简史 (下)
- Linux如何终止D状态的进程
- 文创雪糕火出圈!是真内卷还是真搞笑?
热门文章
- Scratch编程(十)扩展模块:视频侦测模块
- python中reduce函数_reduce函数
- 全球及中国智能家居设备市场竞争态势与投资策略建议报告2022版
- 误差条图各部分的代表意思_【小强视界】混凝土搅拌站计量误差原因分析及控制措施...
- 基于MySQL毕业设计题目50例
- c语言航标知识点,书摘:迷惘时的航标——“人生哲学”
- 学校计算机怎么连接自己的热点,笔记本电脑怎么连接手机热点(手机热点开启及连接方法)...
- 使用IDEA工具远程调试SpringBoot应用
- 设备屏幕亮度调节代码实现
- 程序员之网络安全系列