使用单线程创建数据库连接 + 数据库连接没有配置超时 socketTimeout,造成挂起2小时11分钟无法获取新连接,系统必须重启。
挂起场景:握手阶段 "Druid-ConnectionPool-Create-664205978" #31 daemon prio=5 os_prio=0 tid=0x000000001934f000 nid=0x3930 runnable [0x000000001ecbe000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:150) at java.net.SocketInputStream.read(SocketInputStream.java:121) at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114) //挂起 at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161) at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189) - locked <0x00000000c6972650> (a com.mysql.jdbc.util.ReadAheadInputStream) at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3163) at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:600) at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1088) //握手请求 at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2493) at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2526) //获取单个连接 at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2311) - locked <0x00000000c69727a0> (a com.mysql.jdbc.JDBC4Connection) at com.mysql.jdbc.ConnectionImpl.(ConnectionImpl.java:834) at com.mysql.jdbc.JDBC4Connection.(JDBC4Connection.java:47) at sun.reflect.GeneratedConstructorAccessor76.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:408) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:416) at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:347) at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156) at com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:218) at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1598) at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1662) at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2601)
https://www.codeleading.com/article/6202689267/
tcp_syn_retries 默认值:5 功能:对于一个新建的TCP连接(主动发起),内核要发送多少个SYN连接请求才决定放弃。这个值不应该超过255。默认值为5,对应180s
tcp_keepalive_time 默认值:7200(2小时)。单位-秒 功能:对于一个保活的TCP连接,该值设定了TCP多长时间发送一次keepalive消息(简单来说就是心跳检测周期)
tcp_keepalive_probes 默认值:9 功能:在内核决定放弃该连接之前,发送多少个keepalive探测
tcp_keepalive_intvl ** 默认值:75 功能:设定keepalive探测发送频率。 对于发出的keepalive探测消息没有收到响应时,则根据这个intvl值设定的间隔再次发送。 用这个intvl值probes值,得到的是发送探测共消耗的时间,默认是11分钟。9*75/60=11min。 如果在这11分钟内还没有收到探测响应,则丢弃该TCP连接。
生产环境2小时11分钟,才能从失败中重连,和上面3个参数刚好一致。
Druid连接池,是否能够提供一个后备方案在多长时间没有连接成功后, 重新发起连接?
原提问者GitHub用户GuoHuiChen
在使用单线程创建数据库连接时,如果连接没有配置超时 socketTimeout,可能会导致连接挂起,进而导致程序长时间等待而陷入阻塞状态。
配置 socketTimeout 的作用是设置连接的超时时间,当连接在指定的时间内没有响应时,会抛出超时异常,从而避免连接挂起的情况。建议在连接数据库时,根据实际情况设置合适的 socketTimeout 值,以避免连接挂起的风险。
同时,在使用单线程创建数据库连接时,需要注意连接的使用和释放,以避免连接泄漏或者过多占用连接资源的情况。建议使用连接池等技术来管理数据库连接,以提高连接的重用率和效率,并避免连接资源的浪费。
Druid连接池支持配置一个超时时间,可以在连接池创建时传递一个超时时间参数。例如,可以使用如下代码创建一个连接池,该连接池在2小时11分钟内没有成功连接时会重新发起连接
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。