RCA:JDBC驱动自身问题引发的FullGC

郑昀 基于田志全和端木洪涛的分析报告 2015/6/30

关键词:Java,JDBC,升级,MySQL驱动,频繁数据查询,mysql-5.1.34,mysql-5.0.7

问题现象:

2015年4月22日(周日)晚间,线上 TaskMall 工程(一个 Java 工程)频繁报警。分析 jvm 情况,taskmall 在内存使用上确实存在问题,可能有大量对象不正常堆积:

图2 155 jmap

问题原因:

频繁的大数据查询场景下,mysql-5.1.34 驱动的性能远优于 mysql-5.0.7 驱动。一定要及时升级驱动啊。

RCA类型:

维护问题。

其实我们在RCA(Root Cause Analysis)第四季就曾经遇到此类问题:


第四季案例5 官方驱动也会设计不当,及时升级

——实例

2013年1月,由于 PHP 一直使用 MongoDB PHP Driver 1.2.x 驱动,导致 PHP-FPM 模式下,每一个 PHP Worker 进程都有自己独立的 mongodb 连接池,从而导致连接数极易超标,占用内存数也随之倍增,MongoDB 负载很重。

如当时编辑后台192 --> mongodb-165 之间的连接数基本维持在:750~751个左右。

升级到 mongodb-php driver 1.3.2 驱动之后,日常连接数大为下降。

——教训:

引入了重要存储介质的驱动之后,如spymemcahced、mongodb php/java driver、jedis等,保持跟踪它们的动态,第一时间更新驱动。

问题分析:

志全分析堆栈信息发现,系统中有大量的 CancelTask 定时任务需要执行。

图3 大量的CancelTask

为什么会有这么多的任务呢?

这是 mysql 的一个定时任务,主要用于查询超时处理。即,系统在执行一个 sql 查询时,jdbc 会给你一个超时时间。为了保证超时时间后,能够关闭 statement,会打开一个保护关闭的定时任务。如果超时情况下,sql 还没响应执行,cancel task 就会执行关闭任务。注,ibatis 的默认超时时间为3秒(<setting name="defaultStatementTimeout" value="3000" />)。

图4 mysql源码

其实,cancel() 方法只是对状态做了一个标记而已:

图5 mysql源码

只有在调度任务时,发现状态为取消,才会真正移除该任务:

图6 mysql源码

于是,在某些情况下,CancelTask 会大量累积,从而严重影响 JVM 内存,最终引发 FullGC!

问题解决:

志全分析了 MySQL 最新的 jdbc 驱动,发现 CancelTask 在 mysql 驱动中,后续的版本已经不采用全局的 Timer 任务池了。

在 mysql-connector-java-5.0.7-bin.jar 中:

图7 mysql源码

而在 mysql-connector-java-5.1.34-bin.jar 中:

图8 mysql源码

端木洪涛经过针对性的压力测试,确实证实了这个现象可以重现。测试报告如下所示:


测试时间:2015年4月29日

使用taskmall联调环境做测试。

协调器:10.8.210.168

分发器:10.9.210.151、10.9.210.152

执行器:10.9.210.154

分发器配置如下:

151使用mysql-5.1.34驱动,152使用mysql-5.0.7驱动其中分发器两机器为2核8G配置,统一resin4 JVM配置:

<jvm-arg>-Xmx1024M</jvm-arg>
               <jvm-arg>-Xms1024M</jvm-arg>
               <jvm-arg>-Xmn512M</jvm-arg>
               <jvm-arg>-XX:SurvivorRatio=6</jvm-arg>
               <jvm-arg>-Xss1024k</jvm-arg>
               <jvm-arg>-XX:PermSize=256M</jvm-arg>
               <jvm-arg>-XX:MaxPermSize=256M</jvm-arg>

基础准备:

1、往数据库中压入5180条队列数据,(其中151机器分的2614条,152机器分得2566条);

2、改造执行器,使其只接受数据不处理数据。则5180条数据对分发器来说一直都是有效数据;

3、改造分发器,设置ibatis参数:cacheModelsEnabled="true"、defaultStatementTimeout="3000"。每150ms加载一次数据;

(分发器起16个线程对应16个cobar分库,每个线程分页加载分库中的有效数据,每页200条数据。)

4、jvisualvm远程监控151、152机器。

测试结果如下:

一、15分钟后监控结果如下

从图上看出152机器从cpu占用、堆大小在逐渐升高,查看gc日志发现152已经开始出现FullGC。

 

152机器已快挂:

151机器则一切正常:

二、32分钟后监控结果如下

此时除了cpu占用、堆飙高外,152的线程数也远远高于151。此时的152已经频繁FullGC了。

152机器:

151机器则:

统计堆内存中活着对象数据:

152机器出现大量的Byte数据以及PreparedStatement,以及CancelTask。

1)但是在151机器上前47位的占用排行上找不到CancelTask。

2)在byte数据量上,152机器达到了600M,而151机器只有几十M。

测试结论:

频繁的大数据查询场景下,mysql-5.1.34 驱动的性能处理远优于 mysql-5.0.7 驱动。

-EOF-

时间: 2024-10-07 19:47:38

RCA:JDBC驱动自身问题引发的FullGC的相关文章

maven添加sqlserver的jdbc驱动包

http://search.maven.org/中没有sqlserver的jdbc驱动,所以需要本地安装sqljdbc的jar包,然后再在pom里面引入 Step 1 在微软官网下载sqljdbc的jar包:http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=11774 本次下载了4.0版本 空间下载连接分享:https://yunpan.cn/cv3TjJqDZM7zu  访问密码 d6bb Step 2

hibernate 加载 jdbc驱动出错Access to DialectResolutionInfo cannot be null when &#39;hibernate.dialect&#39; not set

Exception in thread "main" org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set程序基本没动过,以前用的3.3.2的版本,今天换成4.3.4的版本后,改了一下sessionFactory的生成方法,其他的不变,开始还能运行,过了30min左右,就不能运行了! hibernate4 已经废弃

在Maven仓库中手动添加Oracle11g JDBC驱动

由于Oracle授权问题,Maven3不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到本地仓库 手动添加oracle 11g JDBC 驱动  mvn install:install-file -Dfile=D:/ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1.0 -Dpackaging=jar 命令执行后 将D:/ojdbc6.

MySQL版本与JDBC驱动的问题

我用eclipse写struts的注册页面的时候,出现了这个问题,我上网查了一下,有人说这个数据库表的引擎问题,我查看了引擎发现没有问题,还有人说是JDBC版本的问题,我就试着去更改我的JDBC的驱动版本,还真解决了问题,我出现的错误提示如下: java.sql.SQLException:Could not retrieve transation read-only status server atcom.mysql.jdbc.SQLError.createSQLException(SQLErr

java连接sql server 2008的问题(jdbc驱动的方法)

这是程序代码,我是按照网上和视频讲解的步骤写的代码:import java.sql.*;public class jdbc {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubConnection ct = null;PreparedStatement ps = null;ResultSet rs = null;try {//第一步,加载驱动Class.forNa

转:JDBC驱动配置相关

1.做JDBC请求 ,首先要了解这个JDBC对象是什么,现在以SQLServer为例来说明 首先下载对应的数据库驱动(百度“jdbc sqlserver驱动”,然后下载). 注意 :下载完成后,直接把sqljdbc4.zip改为jar的后缀名.然后放到 放在jmeter的\lib目录下,例如C:\jmeter-2.13\lib. 2. 至于创建Jmeter工程这里不再详述,直接参看下图( 添加配置元件 JDBC Connection Configuration ) 关于以上的URL和JDBC驱动

转: Maven 仓库中添加Oracle JDBC驱动(11g)

1.由于Oracle授权问题,Maven3不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到本地仓库,此文档用的是Oracle 11g.通过Oracle的安装目录获得,位置在:E:\app\zhaoheng\product\11.2.0\dbhome_1\jdbc\lib下: 此使用的是ojdbc6.jar 2.知道自己安装的Oracle是什么版本的 可以在SQL窗口中输入:select * from v$instance

[Java] Oracle的JDBC驱动的版本说明

classes12.jar,ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别,之间的差异 作者:赵磊 博客:http://elf8848.iteye.com 来源:http://elf8848.iteye.com/blog/811037 在使用Oracle JDBC驱动时,有些问题你是不是通过替换不同版本的Oracle  JDBC驱动来解决的?最常使用的ojdbc14.jar有多个版本,classes12.jar有多个版本你了解吗? 连接类型: 1.JDBC OCI: o

HBase JDBC驱动Phoenix与SpringJDBCTemplate的集成

Phoenix:Phoenix将SQL查询语句转换成多个scan操作,并编排执行最终生成标准的JDBC结果集. Spring将数据库访问的样式代码提取到JDBC模板类中,JDBC模板还承担了资源管理和异常处理的工作,Phoenix作为JDBC驱动同样可以将其与Spring集成,提高开发效率. 具体操作如下: 1.配置applicationContext.xml <beans xmlns="http://www.springframework.org/schema/beans" x