错误一:get connection timeout retry : 1

https://github.com/alibaba/druid/issues/4326

生产环境运行一段时间后,报错如下:

com.alibaba.druid.pool.DruidDataSource : get connection timeout retry : 1
com.alibaba.druid.pool.DruidDataSource : get connection timeout retry : 1
com.alibaba.druid.pool.DruidDataSource : create connection SQLException, url: jdbc:oracle:thin:@x.x.x.x:1521:orcl, errorCode 17002, state 08006
java.sql.SQLRecoverableException: IO Error: Connection reset
Caused by: java.net.SocketException: Connection reset
c.a.druid.pool.DruidAbstractDataSource : {dataSource-1} failContinuous is true

此时连接并没有到达最大连接数,一直复现不了问题,花了不少时间才定位到原因 :

并发获取连接的个数超过”最大并发连接数“导致。但此时连接数远远未到达最大连接数。

select count(*) from v$session where status='ACTIVE' --最大并发连接数

查询结果:23

还原测试:

设置获取连接超时时间为6秒

###程序向连接池中请求连接时,超时时间,毫秒
spring.datasource.druid.max-wait=6000

测试代码:

		int N = 50;
		CountDownLatch countDownLatch = new CountDownLatch(N);// 实例化一个倒计数器,N指定计数个数
		for (int i = 0; i < N; i++) {
			new Thread(() -> {
				Connection connection = null;
				try {
					// 执行代码
					countDownLatch.countDown(); // 计数减一
					countDownLatch.await();// 等待,当计数减到0时,所有线程并行执行
					connection = jdbcTemplate.getDataSource().getConnection();
					String sql = "select count(*) from v$process";
					PreparedStatement statement = connection.prepareStatement(sql);
					ResultSet set = statement.executeQuery();
					if (set.next()) {
						System.out.println("当前的连接数:" + set.getString(1));
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					try {
						// connection.close();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}).start();
		}

测试代码刚好出现 50-23=27 个错误: get connection timeout retry : 1 

解决办法:

延长获取连接超时时间。

###程序向连接池中请求连接时,超时时间,毫秒
spring.datasource.druid.max-wait=180000

但是延长获取连接超时时间的办法,治标不治本。

保持连接池最小连接数,避免突然大量并发创建连接,来最终解决问题。

spring.datasource.druid.min-idle=20

补充:

无论是YGC或是FullGC,都会导致stop-the-world,即整个程序停止一些事务的处理,只有GC进程允许以进行垃圾回收,因此如果垃圾回收时间较长,部分web或socket程序,当终端连接的时候会报connetTimeOut或readTimeOut异常

错误二:java.sql.SQLRecoverableException: 无法从套接字读取更多的数据

测试:

## 配置间隔多久才进行一次检测(检测需要关闭的空闲连接),单位是毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000

在使用连接后60秒内杀掉session ,并再次使用连接查询数据库。

#登陆到oracle用户
su - oracle

#杀掉所有session
ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCAL=NO|awk '{print $2}'|xargs kill -9

在配置的空闲连接时间 60秒内 如果发生网络异常,Oracle服务端连接已断开,但是客户端连接池并不知道,再次使用就会报错:

java.sql.SQLRecoverableException: 无法从套接字读取更多的数据

解决办法:

#程序 申请 连接时,进行连接有效性检查(低效,影响性能)
spring.datasource.druid.test-on-borrow=true

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐