Skip to content
New issue

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

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

Already on GitHub? # 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再看看

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

No branches or pull requests

5 participants