解决com.mysql.jdbc.NonRegisteringDriver的内存泄漏

因为游戏的服务端是用Java编写的,大量使用了缓存和数据异步写入机制,但在运行的过程中要大量记录运营日志,所以数据库的读写虽然可能不像web服务器那样频繁,但数据库的开销其实还是相对可观的。上线运营一段时间后,服务器越来越卡,而且还出现Out Of Memory的情况。

分析一:使用jmap命令观察到Jvm的GC已经到了很危险的情况,JVM的新生代和老年代都几乎已经消耗完毕了,如下图。

分析二:继续查看JVM 的GC日志,下面摘抄几条:

2014-05-16T13:57:23.958+0800:592015.629: [Full GC 1948862K->1943518K(2024256K), 0.8818560 secs]

2014-05-16T13:58:10.682+0800: 592062.352:[Full GC 1948862K->1943638K(2024256K), 1.0139730 secs]

2014-05-16T13:59:18.427+0800: 592130.097:[Full GC 1948862K->1943686K(2024256K), 0.9705680 secs]

FULL GC出现的情况越来越频繁, 到了最后隔几秒就要Full GC一次,而且所需要的时间越来越长,Minor GC 已经几乎不出现了,与上图中的情况完全吻合。

分析三:使用jmap-dump:format=b,file=logic_heap.hprof pid这个命令,dump出内存的映像状态文件,再使用MemoryAnalyzer这个工具分析。发现有大量的com.mysql.jdbc.NonRegisteringDriver这个对象产生泄漏。这个类是MySQL的connector/J官方驱动,按道理是不用出大问题的,我一开始也是从来没怀疑过,而且也不想去碰里面的代码。于是一直分析mybatis的代码,再分析自己封装的dao层。到了最后,实在没办法了,只能把connector/J的源代码打开,发现了里面有一个很重要的变量

ConcurrentHashMap<ConnectionPhantomReference,ConnectionPhantomReference> connectionPhantomRefs

这个map保存了所有连接的实例的虚引用(PhantomReference),然后由AbandonedConnectionCleanupThread不断释放,但最关键的是,似乎PhantomReference的特性是只有当主动调用System.gc()这个方法时才会主动释放(可能我说得不对,但据我观察的情况确定是这样)。而由于之前从一些jvm的调优文章里看到建议不要主动调用System.gc(),因此我整个项目里都从来没主动调用过System.gc()。

最后,解决方法很简单,只要自己写一个定时器,隔一段时间执行一下,就可以源源不断地清理这些PhantomReference



The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:829) at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:449) at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:242) at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:364) at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206) at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:476) at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115) at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:68) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(Abstrac
最新发布
03-12
<think>好的,我现在需要帮助用户解决MySQL连接通信异常的问题,特别是使用HikariCP和Hibernate的情况。首先,我应该回忆一下常见的导致这类异常的原因,并逐步排查可能的因素。 首先,用户提到的是“通信异常”,这可能涉及到网络层面的问题。比如,数据库服务器是否可达,端口是否开放,防火墙有没有阻止连接。这时候,我应该建议用户检查MySQL服务器的运行状态,确认客户端能够通过网络访问到服务器的3306端口(默认端口)。可以使用telnet或者nc命令测试连接,例如: telnet mysql_server_ip 3306 如果连接不通,可能是网络配置问题,需要检查防火墙或安全组设置。 接下来,数据库的配置方面。用户需要确认MySQL的max_connections参数是否足够,避免连接池超过最大连接数导致拒绝连接。同时,连接池的配置,比如HikariCP的maximumPoolSize是否合理,不能超过数据库的最大连接数。另外,空闲连接超时时间(idleTimeout)和最大生命周期(maxLifetime)是否设置得当,避免数据库主动关闭空闲连接,而连接池还在使用它们,导致通信失败。 然后是连接验证的问题。HikariCP有一个connectionTestQuery配置,通常对于MySQL,建议设置为SELECT 1,用于在连接取出池时验证其有效性。此外,MySQL的wait_timeout参数如果设置过短,可能会导致连接被服务器断开,这时候需要调整HikariCP的maxLifetime略小于wait_timeout的值,或者增加MySQL的wait_timeout。 SSL/TLS配置也是一个可能的问题点。如果客户端和服务器之间的SSL配置不匹配,比如强制使用SSL但客户端未配置,或者证书有问题,会导致连接失败。需要检查useSSL参数的设置,根据实际情况调整为true或false。 驱动兼容性方面,用户需要确保使用的MySQL Connector/J版本与MySQL服务器版本兼容。过旧或过新的驱动版本可能导致通信问题,建议使用官方推荐的版本组合。 Hibernate的配置也需要检查,尤其是hibernate.connection.provider_class是否正确设置为HikariCP的提供器,例如: hibernate.connection.provider_class=com.zaxxer.hikari.hibernate.HikariConnectionProvider 此外,Hibernate的方言配置是否正确,例如使用MySQL8的话需要指定MySQL8Dialect。 异常日志分析也很重要。用户应该提供详细的错误日志,特别是通信异常的具体信息,比如“Communications link failure”或“Connection reset”,这些可以帮助定位问题。例如,如果出现“Unable to load authentication plugin 'caching_sha2_password'”,说明MySQL 8默认的身份验证插件与旧版本驱动不兼容,需要更换驱动版本或修改MySQL用户认证方式。 另外,HikariCP的参数配置需要优化,比如leakDetectionThreshold可以检测连接泄漏,connectionTimeout设置合理的等待时间,避免长时间阻塞。 最后,如果问题依然存在,可能需要升级HikariCP和MySQL驱动到最新版本,或者查看社区是否已知类似问题及解决方案。 在给出解决方案时,应该分步骤引导用户检查每个可能的环节,从网络到配置,再到驱动和日志分析。同时,提供配置示例和代码片段,帮助用户更直观地进行调整。另外,生成的相关问题需要围绕这个主题,比如连接池参数优化、认证失败处理、Hibernate集成配置等,以便用户进一步了解相关知识点。</think>### MySQL连接通信异常解决方案(HikariCP + Hibernate) #### 1. 网络层检查 - **确认MySQL服务可达性** 使用命令测试MySQL服务器的网络连通性: ```bash telnet [MySQL服务器IP] 3306 ``` 若连接失败,需检查防火墙、安全组规则或云服务器的网络ACL设置[^1]。 - **检查MySQL用户权限** 确保连接账号具有远程访问权限(非`localhost`): ```sql GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' IDENTIFIED BY 'password'; FLUSH PRIVILEGES; ``` #### 2. 连接池配置优化 在`application.properties`中调整HikariCP核心参数: ```properties # 连接池大小 spring.datasource.hikari.maximum-pool-size=10 # 连接验证语句(MySQL必需) spring.datasource.hikari.connection-test-query=SELECT 1 # 连接最大生命周期(需小于MySQL的wait_timeout) spring.datasource.hikari.max-lifetime=540000 # 9分钟 # 空闲超时检测 spring.datasource.hikari.idle-timeout=300000 ``` #### 3. MySQL服务端配置 修改`my.cnf`关键参数: ```ini [mysqld] wait_timeout = 600 # 控制非交互式连接超时(单位:秒) interactive_timeout = 600 max_allowed_packet=64M # 防止大数据包通信失败 ``` #### 4. SSL/TLS兼容性处理 在JDBC URL中明确SSL模式: ```properties spring.datasource.url=jdbc:mysql://host:3306/db?useSSL=false&serverTimezone=UTC ``` #### 5. 驱动兼容性验证 确保使用与MySQL版本匹配的驱动: ```xml <!-- MySQL 8.x+ 推荐使用8.0.x驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> ``` #### 6. Hibernate集成配置 添加Hibernate特定参数: ```properties # 启用连接提供器 hibernate.connection.provider_class=com.zaxxer.hikari.hibernate.HikariConnectionProvider # 设置MySQL8方言 hibernate.dialect=org.hibernate.dialect.MySQL8Dialect ``` #### 7. 异常诊断方法 - **查看完整错误堆栈** 关注以下关键错误类型: - `CommunicationsException: Communications link failure` → 网络/超时问题 - `Connection reset` → 防火墙/服务端强制断开 - `Public Key Retrieval is not allowed` → 添加`allowPublicKeyRetrieval=true`参数 - **启用HikariCP调试日志** 在`logback.xml`中添加: ```xml <logger name="com.zaxxer.hikari" level="DEBUG"/> ``` #### 8. 高级修复方案 若使用MySQL 8.x出现认证错误: ```sql -- 修改用户密码插件 ALTER USER 'username'@'%' IDENTIFIED WITH mysql_native_password BY 'new_password'; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值