开发者社区> 问答> 正文

连接池启用phyTimeoutMillis之后造成连接泄露

起因

排查发现数据库连接数持续缓慢上涨,进而查看服务中连接数 lsof -Pni | grep mysql ip port 为142条记录,超出maxActive=100的大小 druid版本1.2.8 配置的其他参数除了url user pwd只有如下几条: driver=mysql phyTimeoutMillis = 1小时 minIdle = 5 maxActive = 100

排查 从端口号反查出相应关联的druid维护的连接,排查连接是如何泄露的 1.先找到被泄露端口,把服务无流量2个小时后执行查询端口命令("链接最长使用时间"为1小时,按理不应该还能找到连接) lsof -Pni |grep "xx:3306" java 533 xxx 254u IPv6 xxx 0t0 TCP xx:49682->xx:3306 (ESTABLISHED) 2. 解析找到相关的使用对象 jmap -dump文件,visualvm工具从socket端口号找到相应关联的DruidConnectionHolder对象,下边是排查过程。 使用visualvm 的OQl查询: select s from java.net.SocksSocketImpl s where s.localport == 49682 java.net.SocksSocketImpl(localport=49682) -> MysqlIO -> JDBC4Connection -> druidConnectionHolder(无任何对象引用) 根据查看druidConnectionHolder对象得到以下3条信息,并未过期,并未被关闭,并未正在使用中。

接下来分析DruidConnectionHolder是如何泄露 连接池DruidConnectionHolder[] connections 的修改有如下几个方法: 取出连接polllast、归还连接putLast、定时清理连接shrink。 在shrink方法主要是作链接的保活、丢弃清理, 方法中有个操作对connections数组进行操作 -> System.arraycopy Arrays.fill 这个操作可能会把connections里正常的部分链接置空,如果被置空的DruidConnectionHolder如果还处于年轻代则会很快被finalize清理,而进入了老年代则必须等到"full gc"链接才能回收,就导致了线上服务如果没触发full gc则链接一直保存变成缓慢增长。

尝试解决 shrink 时候为何新建集合保存真正需要留存下来的DruidConnectionHolder,剔除了原有的Arrays.fill逻辑,最后将留存的集合toArray返回给connections,而keepAliveConnections evictConnections 则可以维持原逻辑。

想问下druid的大佬为啥不优化这个bug? DestroyConnectionThread对链接的保活、丢弃后只任意保留一部分,以及shrink操作尽量节省空间少创建集合对象,但是holder泄露会导致socket连接增加且没上限,而设置phyTimeoutMillis一般都是小时级别,被丢弃的DruidConnectionHolder都已经熬到了老年代,只有jvm被触发了老年代清理才有可能释放相应被泄露的链接。或者是隐晦的表明不要继续使用phyTimeoutMillis这个参数了?

T3.png

原提问者GitHub用户huangjinteng

展开
收起
山海行 2023-07-05 16:08:08 449 0
5 条回答
写回答
取消 提交回答
  • 北京阿里云ACE会长

    hyTimeoutMillis 是连接池中的一个参数,用于指定物理连接在多长时间内没有被使用就会被关闭。启用 phyTimeoutMillis 参数可以防止连接长时间占用而无法释放,从而提高连接池的性能和稳定性。但是,如果设置不当,可能会导致连接泄露的问题。

    如果您在启用 phyTimeoutMillis 参数后出现了连接泄露的问题,可能是由于以下原因:

    连接未正确关闭:如果应用程序没有正确释放连接,连接就会一直占用,导致连接泄露。建议在使用连接后,及时调用 close() 方法释放连接。

    连接池配置不当:如果连接池的配置不当,可能会导致连接泄露。例如,连接池中的最大连接数设置过低,可能会导致连接不够用而无法释放。建议根据实际情况调整连接池的配置,以确保连接池的性能和稳定性。

    数据库连接异常:如果数据库连接异常,可能会导致连接泄露。例如,数据库宕机或者网络不稳定等情况。建议在连接异常时,及时关闭连接,并进行相应的处理。

    2023-07-30 21:57:06
    赞同 展开评论 打赏
  • 在连接池的设计中,尽量避免使用phyTimeoutMillis参数过长的设置。较长的phyTimeoutMillis值会导致连接池中的连接长时间得不到释放,进而增加连接的数量。

    优化连接池泄露的解决方案一般包括以下几个方面:

    及时归还连接:确保在使用连接之后,及时将连接归还到连接池中。这样可以避免连接泄露的情况。

    定期检查连接的使用情况:通过监控和定期检查连接的使用情况,及时发现连接泄露的情况,并采取相应的措施进行处理。

    使用连接池的销毁方法:在应用程序关闭或者不再需要连接池时,调用连接池的销毁方法,确保连接池中的连接得到正确的释放和清理。

    2023-07-09 09:59:59
    赞同 展开评论 打赏
  • 1.2.9优化过这个问题。

    原回答者GitHub用户kimmking

    2023-07-06 10:36:08
    赞同 展开评论 打赏
  • 对于数据库连接泄露的问题,你提供了一些排查和分析的结果,并提出了一些关于 Druid 连接池的优化建议。我将尝试回答你的问题和解释相关情况:

    1. 为什么没有优化这个 bug: 从你的描述中,我们可以看出你发现了 Druid 连接池中的一个可能导致连接泄露的问题,并提出了一些优化建议。然而,我作为 ChatGPT 并不是 Druid 的开发者,无法详细了解他们的决策过程。但是通常来说,开源项目的漏洞修复和功能改进都需要开发者评估其优先级、兼容性以及开发资源等因素。如果你认为这个问题十分重要且有广泛的影响,我建议你去 Druid 官方论坛或提交一个 GitHub Issue 来提醒开发者。

    2. phyTimeoutMillis 参数: 你提到设置了 phyTimeoutMillis 参数,一般设置为小时级别。根据 Druid 文档,这个参数指定物理连接在连接池中最长的使用时间(单位为毫秒)。当连接超过该时间时,Druid 连接池会断开连接并将其标记为废弃状态,以便下次清理时被关闭和移除。然而,在连接被废弃后,它只有在 JVM 触发老年代的垃圾回收时才能释放,这可能导致连接泄露问题。

    3. 建议的优化: 你提到了一些关于 shrink 方法的优化建议,包括避免使用 Arrays.fill 操作并通过创建新的集合来保存需要保留的 DruidConnectionHolder。这些优化建议看起来是为了减少空间占用和创建对象的开销。这些改进措施确实可以考虑,但最终是否被采纳取决于 Druid 开发团队对其优先级和可行性的评估。

    需要注意的是,在进行任何优化之前,我们强烈建议你与 Druid 社区或开发者讨论该问题,并确保你理解了所有的影响和风险。他们可能会给出更准确和详细的解释,以及可能的解决方案或工作方式。

    2023-07-05 17:59:55
    赞同 展开评论 打赏
  • 在使用 phyTimeoutMillis 参数后,可能导致连接池中的连接被占用,长时间无法及时释放,进而出现连接泄漏的情况。而 phyTimeoutMillis 参数的作用是设置物理连接在连接池中的最大存活时间,如果长时间没有活动,就会被连接池回收,以防止过期连接占用连接池资源。

    针对此问题,Druid已经在版本1.2.9中进行了优化,在 ShrinkThread 中增加了一个判断:如果连接已经被标记为关闭状态,那么就无需进行回收操作,直接将该 DruidConnectionHolder 对象置为 null,让垃圾回收器回收该对象即可。

    因此,建议将Druid更新到最新版本,以避免该问题。对于已经被回收的连接,如果没有被正确关闭,可能需要考虑优化应用程序代码,确保在使用完连接后及时关闭并归还到连接池中。 另外,建议以较短的时间来设置 phyTimeoutMillis 参数,以便及时释放连接,进而避免连接泄漏的风险。

    2023-07-05 16:57:10
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载