使MySQL Connector重用SSLSessionContextImpl

6

在调查我们Java应用程序中的疑似内存泄漏时,我们发现大量内存被MySQL Connector创建的SSLSessionContextImpl实例使用 - 每个连接一个实例。

这对我们来说成为了一个问题,因为自从OpenJDK 8u222以来,每个SSLSessionContextImpl实例都包含一个缓存,初始容量为(20480 / 0.75) + 1 = 27307(请参见JDK-8210985JDK源代码)。这个加上每半小时创建十个新连接的Hikari连接池(默认行为),意味着一周后我们有约1GB的死SSLSessionContextImpl实例。这些实例在老年代内存池中,并被AbandonedConnectionCleanupThread幽灵引用,我们看到应用由于内存耗尽而死亡(在限制为1GB的Docker容器中),因此我的猜测是,在已经积累的实例上无法及时执行适当的GC。

从表面上看,似乎MySQL连接器的行为不太对,对于同一数据库服务器,它应该重复使用相同的SSLSessionContextImpl - 毕竟, SSLSessionContext接口的JavaDoc(它实现了该接口)说:

SSLSessionContext表示与单个实体关联的一组SSLSessions。例如,它可以与同时参与多个会话的服务器或客户端相关联。

这完美地描述了我们的情况!然而,连接器每次连接都会创建一个新的SSLSessionContext

因此,有两个问题:

  1. 为什么MySQL连接器不重复使用SSLContext?(当然,我们无法读取开发人员的想法 - 但是否有理由不想重复使用它?)
  2. 我们是否可以通过某种方式使其重复使用SSLContext

3
我们遇到了一个类似的情况,Spring Boot 应用程序的内存逐渐增加,直到 GC 开始失控。查看堆转储时,我们发现在 mysql-cj-abandoned-connection-cleanup 线程的 connectionFinalizerPhantomRefs 中持有数百个 sun.security.ssl.SSLSocketImpl。 - Christophe L
1个回答

2

问题一的答案:

MariaDB连接器在CONJ-670中添加了功能,每次都可以创建SSLContext(发布于2.4.0,回溯到1.0.8.0)。这样做的原因是允许密钥库和信任库在运行时动态更改。

解决方法/缓解措施

这不会强制重用SSLContext,但它确实减少了在堆上拥有大量SSLContext的内存占用。

通过添加JVM标志-Djavax.net.ssl.sessionCacheSize=0,可以恢复先前的JDK-8210985行为。

将其设置为0意味着缓存大小实际上是无限的。但实际上,这意味着它最初为缓存分配了少量内存,并允许其无限增长。如果没有这个,缓存的初始容量为27307,相当大!


那个链接看起来像是OpenJDK 7的文档,我猜它没有暴露那个属性? - PMah
抱歉,我只能编辑这个错误的评论5分钟。我们有一个类似的问题。我将尝试设置-Djavax.net.ssl.sessionCacheSize,并额外设置Djavax.net.ssl.sessionCacheTimeout。我在另一个线程上找到了这个第二个JVM属性。我只是想知道JVM属性sessionCacheTimeout如何对应于类SSLSessionContextImpl。似乎没有sessionCacheTimeout属性。http://www.docjar.com/docs/api/sun/security/ssl/SSLSessionContextImpl.html - midnight
谢谢PMah,但即使不在https://devdocs.io/openjdk~8/javax/net/ssl/sslsessioncontext上也行。 - midnight
1
为什么应该将 javax.net.ssl.sessionCacheSize 设置为 0?这意味着有效地将缓存大小设置为无限大,因为它占用了堆的太多空间,而我们正在尝试绑定它。或者是我理解错了什么? - Michele Palmia
你说得对,将其设置为 0 意味着它实际上是无限的。但在实践中,这意味着它最初为缓存分配了一小部分内存,并允许其无限增长。如果没有这个设置,缓存的初始容量为 27307,这相当大! - PMah
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接