【Java】使用jstack、jstat、jmap线上问题排查一例

2024-01-15 10:18

本文主要是介绍【Java】使用jstack、jstat、jmap线上问题排查一例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

现象

前阵子线上发布了一些功能,主要是针对客户群做的社群网络,大数据这边针对用户的通讯录、通话记录、设备等信息,计算其对应的社群网络,然后根据社群对应的指标来判断用户的风险情况。当然新老用户的逻辑有所区分,这里就不再深入阐述了。功能上线后,出现了一个比较诡异的事情:系统CPU和内存都飙升,几乎都快把主机撑爆了。

定位最消耗资源的线程

因为发布是在凌晨,使用app的用户还是比较少的,经过沟通,我们建议运维暂时先不下线新功能。给我们几分钟时间定位问题。这时候我们首先想到要查看是哪个线程最消耗资源。(以下示例为事后线下复现,非当时线上真实资源消耗情况)

  • 查看java进程

ps -ef | grep kafka-1.0 | grep -v grep

93ec254723f7b96fb6e182b1faed8e88.png

  • 查看进程中最消耗资源的线程

在我们查看到进程号以后,可以通过top命令查看对应进程中的线程,以及cpu使用情况

top -Hp 100728

a80fd509765fa38b2e2d81aee627165f.jpeg

  • 转换为十六进制

printf "%x\n" 130870

12f87e7c20bb9e03c2931c1873d16a4b.png

可见线程号为:1ff36

接下来我们就需要用到jstack来查看

jstack 100728 > 100728.jstack

这样我们就把线上应用的堆栈信息给dump下来了,接下来我们可以看看jstack导出的文件主要有哪些内容,以及线程号为:1ff36的线程当时正在进行什么操作。截止目前我们使用的上面的示例实际并不是当时线上的截图,而是后续为了说明当时的场景做的。当时jstack导出的文件我们保留下来了,对应的最占用CPU资源的前几个线程为GC线程。我们有理由认为是内存被撑爆导致的频繁GC,进而导致CPU居高不下。 查看GC情况

/usr/local/jdk1.8.0_11/bin/jstat -gcutil 100728 1000 100

我们发现FGC特别频繁,几秒钟就会进行一次,因为full gc会导致stop the world所以这必然是有问题的,而S0,S1几乎为0,eden区和old区都占满了,即使进行了FGC依然无法回收,由此我们怀疑是在程序运行中产生了大对象无法回收导致频繁FGC: 

df72de034fd9875ac2c7f8a02f8f1475.png

使用IBM的dump文件分析工具

我们先看下jstack下来的文件内容:

c1e380acbe230686f06bfc9967870534.jpeg

推荐大家一个工具:IBM Thread and Monitor Dump Analyzer for Java(点击下载),真的是线程dump文件的分析利器,看起来非常直观。

使用该工具打开dump文件

934b7537240517c8003cf9576b07c704.jpeg

我们发现其中有大量的Waiting on condition等待,它们都是调用的sun.misc.Unsafe.park(Native Method)方法,再看看Thread Details都是hbase连接在获取数据

641699fed700c753357035c81aff2959.jpeg

这里很可能是因为获取了大量的数据导致的内存占用居高不下。但是目前也只能提供一个方向性的参考,并没有定位到具体的开发代码,我们看了这么多wait和调用的方法大多也都是定位到了开发框架的源码。我们可以通过搜索对应项目中的包,看看截止当时应用程序都执行了那些代码,如我们项目中所有的代码都是com.maiya开头的,很幸运目前用户流量还不大,并且调用的程序代码并不复杂,我们发现了一个可疑的地方:

1db57c39afb182f5054ca0aef8979545.jpeg

如上图所示,正是本次上线的代码,正在调用hbase的查询接口,那么是否就是hbase表的问题呢,难道如我们上面所猜想的,因为数据量过大导致的出现了大对象?我们count了下对应的表,发现表数据达到了惊人的2亿数据。而且一个用户下有多条重复数据,HBase中为什么会有重复数据呢?原来是因为key设计的问题,导致本该覆盖的记录,并没有覆盖,而是新增了。在数据重复统计多次以后,数据量猛增。最终导致了上面的问题。

至此已经定位出来原因了,程序并不需要进行修改,只要对HBase表进行重构,数据入库逻辑修改即可。数据修正后,程序重启后也正常了。 实际上我们也可以通过jmap查看程序中的class对象占用内存情况。不过dump出来的文件一般都比较大,大家要慎重。

使用java自带的jvisualvm,可以分析heap.hprof文件中的内容:

ec541b9ac49719f7f8a8364bbf8e8184.jpeg

使用jstack只能复现当时线程的方法栈,是一个静态的场景,所以一般要多导出几次,分析对比,如果某个应用程序线程在多次的jstack文件中一直存在,那么可能就需要我们多加关注了。

这篇关于【Java】使用jstack、jstat、jmap线上问题排查一例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/608554

相关文章

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹

Java中的stream流分组示例详解

《Java中的stream流分组示例详解》Java8StreamAPI以函数式风格处理集合数据,支持分组、统计等操作,可按单/多字段分组,使用String、Map.Entry或Java16record... 目录什么是stream流1、根据某个字段分组2、按多个字段分组(组合分组)1、方法一:使用 Stri

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

使用Python的requests库来发送HTTP请求的操作指南

《使用Python的requests库来发送HTTP请求的操作指南》使用Python的requests库发送HTTP请求是非常简单和直观的,requests库提供了丰富的API,可以发送各种类型的HT... 目录前言1. 安装 requests 库2. 发送 GET 请求3. 发送 POST 请求4. 发送