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异常
测试:
## 配置间隔多久才进行一次检测(检测需要关闭的空闲连接),单位是毫秒
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