侧边栏壁纸
博主头像
东家博主等级

东家不是家,心里有个她!

  • 累计撰写 6 篇文章
  • 累计创建 8 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

线上Full GC问题排查之inner join连接查询

Administrator
2023-05-22 / 0 评论 / 0 点赞 / 55 阅读 / 3164 字

背景

项目上线之后,出现系统卡顿获取接口无响应,这时查看服务器的各项指标监控,能看到JVM中有像下图类似的FGC的情况 ,但是对于后续怎么去解决,有些同学可能没有清晰的思路。

image-20230708155821214

这篇博客主要就通过分享一个具体的例子,给大家提供分析定位解决问题的一个思路

问题定位

添加JVM参数

-XX:+HeapDumpOnOutOfMemoryError //oom时自动dump
-XX:+HeapDumpBeforeFullGC //fgc前自动dump
-XX:+HeapDumpAfterFullGC //fgc后自动dump
-XX:HeapDumpPath=/opt/dump //指定dump文件生成路径

分析dump文件

通过MAT下载地址 根据JDK版本选择MAT版本工具分析FGC 前后的dump文件可以比较容易的帮我们找到出问题的地方,下面是油卡dump文件分析的例子

FGC前

image.png

FGC后

image.png

分析报告的第一个问题有明显的区别,点开GC前suspcet1的detail

image.png

可以看到树中累积对象大小,其中com.mysql.jdbc.JDBC42ResultSet中积累了大量的com.mysql.jdbc.ByteArrayRow,我们选中com.mysql.jdbc.JDBC42ResultSet -> List Objects -> with outgoing references 可以看到对象中的详细信息

image-20230708155952339

其中能看到SQL:

SELECT d.is_deleted FROM oil_write_off_xxxxx d, oil_request_funds_trading t WHERE t.request_funds_serial_no = 'Q001548592'

返回了三十六万多条数据,到这里就基本定位了FGC的原因

问题解决

定位SQL

思路1:在项目中搜索

SELECT d.is_deleted FROM oil_write_off_xxxxx d, oil_request_funds_trading t WHERE t.request_funds_serial_no = 'Q001548592'

这个SQL的相关代码,结果相关的SQL只有一条更新的语句

image.png

思路2:由于OOM是SQL引起的,那应该能关联到具体的请求,可以去Pinpoint上找到对应的请求查看调用链。根据OOM的时间去Pinpoint上查询相关的请求,时间在9:40-9:50之间

image.png

在9:40-9:50中间有一个错误请求,我们直接点进去看调用链

image.png

可以看到在更新语句之后执行了一个**selectBySql(String sql)**的方法,这个方法里面的SQL正好就是我们引起OOM的SQL,这个SQL作用是将之前的数据记录下来作为日志变化前数据,然后在执行update语句,代码如下:

// 省略
} else {
    // 获取查询老值的sql
    String selectSql = getSelectSQL(sqlInfo);
    ActionLogService actionLogService = SpringContext.getApplicationContext().getBean(ActionLogService.class);
    List<Map<String, String>> oldParamList = actionLogService.selectBySql(selectSql);
    originalValue = DEFAULT_OBJECT_MAPPER.writeValueAsString(oldParamList);
	// 执行业务操作
}
// 省略

由于update语句中使用了inner join 关联了一张辅表,where查询条件后面只有主表的条件,所以在生成的select语句中,辅表的数据会全都被拉出来。

解决

在SQL解析中增加对update语句中join的判断,如果包含join,则不去执行查询更新前数据的逻辑

0

评论区