Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.2.6版本中仍然存在同一个holder在connections出现两次的问题,高并发下会出现statement is closed等问题。 #4316

Closed
Linliangkung opened this issue Jun 7, 2021 · 9 comments
Assignees
Labels
Milestone

Comments

@Linliangkung
Copy link

Linliangkung commented Jun 7, 2021

1.druid配置参数如下:

minEvictableIdleTimeMillis=100000
setMaxEvictableIdleTimeMillis=1000L * 60L * 60L * 7
keepAliveBetweenTimeMillis=120000
minIdle=2
timeBetweenEvictionRunsMillis=70000
validationQuery=select 1
keepAlive=true

2.测试代码如下:

    DruidDataSource druidDataSource = new DruidDataSource();
    druidDataSource.setUsername("");
    druidDataSource.setPassword("");
    druidDataSource.setUrl("jdbc:mysql://192.168.253.129:3306/user?characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=false&allowMultiQueries=true");
    druidDataSource.setValidationQuery("select 1");
    druidDataSource.setMinEvictableIdleTimeMillis(100000);
    druidDataSource.setMaxEvictableIdleTimeMillis(DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS);
    druidDataSource.setKeepAliveBetweenTimeMillis(120000);
    druidDataSource.setMinIdle(2);
    druidDataSource.setTimeBetweenEvictionRunsMillis(70000);
    druidDataSource.setKeepAlive(true);
    DruidPooledConnection connection1 = druidDataSource.getConnection();
    DruidPooledConnection connection2 = druidDataSource.getConnection();
    connection2.close();
    Thread.sleep(95000);
    connection1.close();
    Thread.sleep(140000);
    DruidPooledConnection connection3 = druidDataSource.getConnection();
    DruidPooledConnection connection4 = druidDataSource.getConnection();
    System.out.println(connection3.getConnectionHolder() == connection4.getConnectionHolder());
    connection3.close();
    connection4.close();

3.运行结果:

WeChataf416ae5c667d16927a3672603e2bf03

WeChatc2cbaecdf44f96bee8cb8a21fdf34a92

4.原因分析:

问题出现在DestoryTask的shrink函数中。
时间点70000ms时:connections[connection2],connection2的空闲时间均小于minEvictableIdleTimeMillis和keepAliveBetweenTimeMillis跳过

时间点95000时,connection1返还连接池,此时connections[connection2,connection1],connections中的元素空闲时间是递减的

时间点140000ms时,connection2因为空闲时间大于120000会加到keepConnections数组中,后返还,返还时未修改lastActiveTimeMillis,此时connections[connection1,connection2],connection2的空闲时间比connection1的要大

时间点210000ms时,connections1因为空闲时间大于100000,但由于设置minidel=2会跳过shrink中所有if代码块,connections2由于空闲时间大于120000,会加入keepconnection中。进而导致connections会有两个相同的holder

5.总结:

1.2.6版本中限制timeBetweenEvictionRunsMillis小于keepAliveBetweenTimeMillis并不能解决问题。该问题出现的原因还是shrink函数中connections拷贝的bug,希望官方能解决这个bug,可参考pullrequest:#4218

另一方面keepConnection放回connections未修改lastActiveTimeMills,会导致connections的空闲时间不是递减的。

@wenshao

@ifangta
Copy link

ifangta commented Jun 22, 2021

这里并发多大会发生,我这边用最新版本,并发在56个就频繁的出现。

@Linliangkung
Copy link
Author

Linliangkung commented Jun 22, 2021

这里并发多大会发生,我这边用最新版本,并发在56个就频繁的出现。

导致这个问题的根本原因不是因为并发高,是某种特定场景下,连接池持有了两个相同的连接。在高并发下会相互影响。
你可以尝试把keepAliveBetweenTimeMillis的配置设置小于minEvictableIdleTimeMillis暂时可以避免这个问题的出现。但彻底解决问题要等官方回应了。

@solan
Copy link

solan commented Jun 27, 2021

@Linliangkung 请问你给的例子也是

keepAliveBetweenTimeMillis大于minEvictableIdleTimeMillis

依然也会有重复链接的问题。

为何说用这个配置可以暂时避免这个问题?

@Linliangkung
Copy link
Author

@Linliangkung 请问你给的例子也是

keepAliveBetweenTimeMillis大于minEvictableIdleTimeMillis

依然也会有重复链接的问题。

为何说用这个配置可以暂时避免这个问题?

写错了,是小于

@solan
Copy link

solan commented Jun 30, 2021

@Linliangkung 感谢回复。
把keepAliveBetweenTimeMillis的配置设置小于minEvictableIdleTimeMillis就可以保证不会有重复连接吗?

由于keepConnection放回connections未修改lastActiveTimeMills,会导致connections的空闲时间不是递减的。

例如[a,b,c,d] c和d是keep alive后放回的连接,那么c和d的lastActiveTimeMills大于a和b,下次还是有可能c和d放入keepaliveconnections,导致连接重复。不知道我理解的对不对。

@BruceZhangXL
Copy link

+1

@BruceZhangXL
Copy link

@Linliangkung 把keepAliveBetweenTimeMillis的配置设置小于minEvictableIdleTimeMillis就可以保证不会有重复连接吗? 你试过吗

@Linliangkung
Copy link
Author

@Linliangkung 把keepAliveBetweenTimeMillis的配置设置小于minEvictableIdleTimeMillis就可以保证不会有重复连接吗? 你试过吗

可以,能保证

@BruceZhangXL
Copy link

@Linliangkung 把keepAliveBetweenTimeMillis的配置设置小于minEvictableIdleTimeMillis就可以保证不会有重复连接吗? 你试过吗

可以,能保证

minEvictableIdleTimeMillis=180000
setMaxEvictableIdleTimeMillis=180000
keepAliveBetweenTimeMillis=120000
minIdle=4
timeBetweenEvictionRunsMillis=6000
validationQuery=select 1
keepAlive=true

依然会出现 statement is close,不过我用的druid是 1.1.22版本,我升到1.2.6再看看

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants