使用多种工具进行JVM调优、线上故障排查的例子

news2024/11/20 23:22:15

1 FullGC调优

面试官:如何进行 JVM 调优(附真实案例)

2 使用arthas诊断案例

2.1 使用arthas确定某一个耗时的请求来自哪一个controller,并且分析以及代码优化

2.1.1 为什么要做第一步的“确定请求来源的controller”?

分析:首先我们需要知道我们想要分析哪一个请求,比如用户登录请求,其次我们需要了解springMVC的特性,我们知道所有的请求都会走DispatcherServet这个类,然后会从一个getHandler的方法中返回给DispatcherServet处理该请求的controller。

2.1.2 第一阶段:找到具体的处理方法

  1. 所以我们的重点就是直接使用watch命令观测这个getHandler方法的输入参数和返回值;
watch org.springframework.web.servlet.DispatcherServlet getHandler 'returnObj'
  1. 然后在前端或者postman上触发一次这样的请求,比如我这里触发登录请求。

3. 查看得到的哪些controller:
通过下面的标红的部分,可知这个登录请求经过了UserController控制器的login方法,和StudentController控制器的findAll方法。
在这里插入图片描述

2.1.3 第二阶段:分析

  1. 入参和返回值分析:使用watch命令观察这个具体的controller中的处理方法的入参和返回值
watch com.itheima.controller.* * '{params,returnObj}' -x 2

得到的结果如下所示:

method=com.itheima.controller.UserController.login location=AtExit
ts=2023-08-21 20:55:52; [cost=5.2786ms] result=@ArrayList[
    @Object[][
        @User[User{id=null, name='newboy', password='123'}],
        @StandardSessionFacade[org.apache.catalina.session.StandardSessionFacade@2a57d000],
    ],
    @String[forward:/student/list],
]
method=com.itheima.controller.StudentController.findAll location=AtExit
ts=2023-08-21 20:55:52; [cost=6.0088ms] result=@ArrayList[
    @Object[][isEmpty=true;size=0],
    @ModelAndView[
        view=@String[list],
        model=@ModelMap[isEmpty=false;size=1],
        status=null,
        cleared=@Boolean[false],
    ],
]
  1. 调用链路和节点耗时分析:使用trace命令得到这个控制器处理方法的调用链路以及各个节点上耗费的时间

trace com.itheima.controller.* login

在这里插入图片描述
我们发现这个controller调用了"com.itheima.service.UserService:login()"这个最耗时的方法

  1. 于是我们可以继续分析这个业务层的login方法

trace com.itheima.service.UserService login

结果如下所示:我们发现最耗时的还是访问数据库的com.itheima.dao.UserDao:login()方法,由此可见,IO操作往往占用处理一个请求的绝大多数时间

Affect(class count: 3 , method count: 2) cost in 78 ms, listenerId: 12
`---ts=2023-08-21 21:10:42;thread_name=http-nio-8080-exec-3;id=1a;is_daemon=true;priority=5;TCCL=org.apache.catalina.loader.ParallelWebappClassLoader@64e2f243
    `---[7.7167ms] com.sun.proxy.$Proxy25:login()
        `---[28.93% 2.2322ms ] com.itheima.service.impl.UserServiceImpl:login()
            `---[98.83% 2.206ms ] com.itheima.dao.UserDao:login() #17
  1. 查看这个生成的代理方法,并且使用jad命令反编译

jad com.sun.proxy.$Proxy24 login

ClassLoader:

  +-java.net.URLClassLoader@1c4af82c
    +-sun.misc.Launcher$AppClassLoader@764c12b6
      +-sun.misc.Launcher$ExtClassLoader@3d82c5f3

Location:

public final User login(User user) {
    try {
        return (User)this.h.invoke(this, m3, new Object[]{user});
    }
    catch (Error | RuntimeException throwable) {
        throw throwable;
    }
    catch (Throwable throwable) {
        throw new UndeclaredThrowableException(throwable);
    }
}

2.1.4 第三阶段:代码优化

  1. sql优化:

注意:此项目中最耗费时间的方法是一个路径为com.sun.proxy.$Proxy25:login()的代理方法,这个方法是mybatis插件生成的,一般我们不能对其进行改动,如果访问数据库确实非常耗时,那也是去修改sql语句以及调整数据库的相关参数

  1. 如果是处理请求的业务层方法非常耗时,那一般我们的代码优化涉及到修改字节码文件,所以需要事先使用dump命令将这个业务方法所在的字节码文件保存到另一个目录中;假设我们第6步中的得到具体实现类-com.itheima.service.impl.UserServiceImpl:login()方法非常耗时,我们现在需要改进他

保存UserServiceImpl这个类到另一个目录以便恢复,

dump com.itheima.service.impl.UserServiceImpl > /root/UserServiceImpl.java

反编译UserServiceImpl实现类到指定目录,

jad --source-only com.itheima.service.impl.UserServiceImp > /root/UserServiceImpl.java

在本地idea或者在vim编辑器中修改 /root/UserServiceImpl.java文件,并且使用mc命令编译这个java文件到/root/bbb/目录下

mc -d /root/bbb/ /root/UserServiceImpl.java

使用redefine命令加载新的字节码

redefine /root/bbb/UserServiceImpl.class

3 OOM的故障如何排查和解决

当Java应用程序抛出OutOfMemoryError(通常简称为OOM)时,表示JVM无法为对象分配更多的内存,因为它已经耗尽了可用的内存。以下是排查和解决OOM的一般步骤:

  • 查看错误信息:OOM错误消息通常会给出更多的上下文,例如是否是堆内存溢出 (java.lang.OutOfMemoryError: Java heap space) 还是元空间溢出 (java.lang.OutOfMemoryError: Metaspace)。

  • 生成堆转储:当发生OOM时,可以配置JVM生成堆转储(heap dump)。这可以通过JVM参数实现:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump。堆转储文件可以使用工具如Eclipse MATVisualVM进行分析,找出占用大量内存的对象。

  • 监控工具:使用像VisualVMJConsoleGrafanaPrometheus等工具,实时监控JVM的内存使用情况。

  • 分析日志:检查应用程序和服务器的日志,寻找任何异常的行为或长时间运行的任务。

  • 代码审查:寻找可能的内存泄露来源,例如长时间存活的大对象、集合类没有正确清除、数据库连接没有关闭等。

  • 调整JVM参数:可以考虑增加堆内存限制(-Xms-Xmx),但这只是短期解决方案。长期来看,还是需要找出OOM的根本原因。

4 如果是因为某一个运行时的SQL语句查询出的数据量太大导致堆OOM,这种如何定位到这条SQL语句?

  • 日志:查看数据库查询日志和应用程序日志,看是否有长时间运行的大查询。启用SQL慢查询日志可能对此有帮助。

  • 监控工具:许多数据库都有监控工具,如MySQL的Performance SchemaInformation Schema,可以查看正在运行或最近执行的查询。

  • 堆分析:OOM时生成的堆转储可以显示哪些对象占用了大量的内存。例如,如果你使用Hibernate,可能会看到大量的Hibernate实体。

  • 分析代码:检查代码中的数据库查询,特别是那些可能返回大量数据的查询。考虑是否真的需要加载所有这些数据,或者是否可以分批加载或进行更多的过滤。

  • 应用监控工具:工具如New RelicDynatraceElastic APM等可以监控应用程序性能和数据库查询,帮助你定位高开销的查询。

总之,处理OOM需要系统地排查和多角度的分析。对于数据库查询导致的OOM,重点是优化查询和合理地管理内存使用,例如分页、使用流处理等。

5 大厂实习时的线上OOM故障排查,并且优化代码的case

5.1 背景

在大厂实习期间,接过一个需求是进行数据同步操作,将lldp接线和build的接线进行比较判断,lldp接线记录数据中心初始的接线状况,build为规划建设中的接线状况,规划建设的未实际实施的,而建设中的是计划实施但是还没有做的,如果实施成功了就会将build的接线数据替换到lldp,然后build用于存储新的建设规划数据。我的这个需求就是需要将lldp和build接线差异做一个比较,将比较信息插入到新的表中,方便数据中心运维人员查看,并且将建设规划的接线覆盖掉lldp中的接线,从而完成接线的建设。

5.2 故障产生的原因

lldp和build模块记录了多个数据中心的内部接线还有跨数据中心的实际接线情况,一开始我直接将测试库中的lldp表中记录的所有数据中心的接线都拿出来了然后放入到一个列表中,然后再取出build中所有的接线,这样两个进行比较。测试的时候没有问题,但是到了线上运行没多久就oom了,经过排查发现是因为这个select * from lldp left jon ... left join .... 语句导致的,因为线上的数据库接线记录得所有数据中心的接线有几十万条,每一条是联表查询的结果,所以当一次性全表查询时就OOM了。

5.3 排查步骤

可以参考第三步,

当Java应用程序抛出OutOfMemoryError(通常简称为OOM)时,表示JVM无法为对象分配更多的内存,因为它已经耗尽了可用的内存。以下是排查和解决OOM的一般步骤:

  • 查看错误信息或者日志:OOM错误消息通常会给出更多的上下文,例如是否是堆内存溢出 (java.lang.OutOfMemoryError: Java heap space) 还是元空间溢出 (java.lang.OutOfMemoryError: Metaspace)。

  • 生成堆转储:当发生OOM时,可以配置JVM生成堆转储(heap dump)。这可以通过JVM参数实现:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump。堆转储文件可以使用工具如Eclipse MATVisualVM进行分析,找出占用大量内存的对象。

5.4 解决方案

使用粒度更小的比较方案,每次只按照单个的数据中心的粒度比较差异,比较完这个数据中心后,再比较下一个数据中心,这样每一个数据中心的接线数量不过10w条。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

切换Debian的crontab的nano编辑器

Debian的crontab默认的编辑器是nano,用起来很不习惯,怎么才能转回vim呢? 用以下命令便可: #update-alternatives --config editor 出现以下所示的界面: 而后选择8使用/usr/bin/vim就能够了。 PS:若是你发现你的定时没有生效&…

全新土地销售活动 Turkishverse——在数字十字路口占据一席之地

准备好与来自该地区的众多世界知名合作伙伴一起探索土耳其文化和历史吧! 简单介绍 ● 在这个弘扬土耳其文化和历史的新社区中,共有 433 块 LAND 可供出售,其中包括 □ 380 块标准 LAND □ 48 块优质 LAND □ 5 个 Estate ● LAND 销售抽…

通达信唐奇安通道指标公式,海龟交易法则的先驱

唐奇安通道(Donchian Channel)是由Richard Donchian发明的技术分析指标,用于确定价格的趋势和波动。著名的海龟交易法则就是基于唐奇安通道设计的,将通道作为交易系统的一部分,用于捕捉趋势信号。唐奇安通道由三条线组…

【腾讯云Cloud Studio实战训练营】React 快速构建点餐页面+Python 拼图小游戏

文章目录 一、腾讯云 Cloud Studio 概述1.1 腾讯云 Cloud Studio 简介1.2 腾讯云 Cloud Studio 功能特点1.3 腾讯云 Cloud Studio 产品优势 二、Cloud Studio界面功能介绍2.1 注册登录2.1.1 新注册用户有免费的3000分钟体验 2.2 界面功能介绍2.2.1 空间模板2.2.2 开发空间关闭空…

二甲医院信息管理系统源码 his系统源码 java+Angular+JavaScript

云HIS系统采用SaaS软件应用服务模式,提供软件应用服务多租户机制,实现一中心部署多机构使用。主要包含收费计费、药品管理、门诊医生工作站、住院医生工作站、护士工作站、数据统计、电子病历、医保接口等功能,能够满足医院及诊所日常业务开展…

VR智慧课堂 | 临床兽医学VR实验教学有哪些好处?

随着科技的不断发展,虚拟现实(VR)技术已经逐渐渗透到各个领域,为人们带来了前所未有的体验。在动物医学实验教学中,VR技术的应用也日益受到关注。本文将探讨临床兽医学VR实验教学的好处。 首先,VR技术能够提高动物医学实验的安全性…

常用数据库备份方法,sql数据库备份方法

在信息时代,数据成为了公司的主要资产。然而,数据的安全性和完整性也成为企业管理的重要组成部分。因此,数据库备份至关重要。本文将详细介绍几种常见的数据库备份方法。 全备份 全备份是指数据库中所有数据的备份,包括数据文件、…

为什么要使用依赖注入?直接new对象不香吗?为什么要把简单的问题复杂化?

作者:newki 为什么要使用依赖注入?直接new对象不香吗?为什么要把简单的问题复杂化? 你是不是在炫技,是不是像装13? 这还真不是,如果说我使用的Dagger2,还真是炫技,NB啊。Dagger的坑…

首轮征稿 | 2024年第二届先进无人飞行系统国际会议(ICAUAS 2024)

会议简介 Brief Introduction 2024年第二届先进无人飞行系统国际会议(ICAUAS 2024) 会议时间:2024年4月5日-7日 召开地点:中国武汉 大会官网:ICAUAS 2024-2024 2nd International Conference on Advanced Unmanned Aerial Systems 由华中科技…

Postgres数据库,使用序列时,没有按自增序列,而且数值很大

文章目录 前言处理前现象原因如何配置序列搞定,再见 前言 最近写了个全局获取操作日志的注解,写在了一个公共模块。但是奇怪的是在有的服务可以自增,而有的不可以。这回中间的过程咱就不过多描述了。 处理前现象 会生成这种id贼大的 原因…

怎么入门网络安全(黑客)?

目录: 一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员(以编程为基础的学习)再开始学习2.不要把深度学习作为入门第一课3.以黑客技能、兴趣为方向的自学误区:4.不要收集过多的资料二、学习网络安全的一些前期准备三…

微信开发之一键邀请好友加入群聊的技术实现

邀请群成员(开启群验证) 若群开启邀请确认,仅能通过本接口邀请群成员 请求URL: http://域名/addChatRoomMemberVerify 请求方式: POST 请求头Headers: Content-Type:application/jsonAuth…

抖音店铺怎么运营?一定要牢记这几个运营细节,能让你少走弯路!

我是王路飞。 新手做抖音小店,一直没做起来不出单的原因,绝大多数都是因为不了解流程,不知道每一步该干什么,以及要做好哪些细节。 不管做什么项目,先入门都是新手的第一要务,只有入门、跑通了整个流程&a…

R包开发-2.2:在RStudio中使用Rcpp制作R-Package(更新于2023.8.23)

目录 4-添加C函数 5-编辑元数据 6-启用Roxygen,执行文档化。 7-单元测试 8-在自己的计算机上安装R包: 9-程序发布 参考: 为什么要写这篇文章的更新日期?因为R语言发展很快,很多函数或者方式,现在可以使…

上传WSL项目到gitlab

上传WSL项目到gitlab 设置ssh将SSH公钥添加到Gitlab 将WSL上的代码上传到gitlab确保在WSL环境中安装了git下面是上传代码到GitLab的具体步骤: 可能遇到的各种错误 设置ssh Gitlab添加SSH KEY 什么是SSH ? SSH 是一种网络协议,具备协议级别的认证及会话…

学习ts(九)装饰器

定义 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上,是一种在不改变原类和使用继承的情况下,动态的扩展对象功能。 装饰器使用expression形式,其中expression必须…

深入Golang之Mutex

深入Golang之Mutex 基本使用方法 可以限制临界区只能同时由一个线程持有。 直接在流程结构中使用 lock、unlock嵌入到结构中,然后通过结构体的 mutex 属性 调用 lock、unlock嵌入到结构体中,但是是直接在需要锁定的资源方法中使用,让外界无…

EMR电子病历系统 SaaS电子病历编辑器源码 电子病历模板编辑器

EMR(Electronic Medical Record)指的是电子病历。它是一种基于电子文档的个人医疗记录,可以包括病人的病史、诊断、治疗方案、药物处方、检查报告和护理计划等信息。EMR采用计算机化的方式来存储、管理和共享这些信息,以便医生和医…

数百个文件夹中的图片批量复制到指定文件夹,按照顺序重新命名

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 最近遇到一个小伙伴问我,怎么将几百上千个文件夹里的文件,批量取出来, 另外汇总放到指定的文件夹中,还要从1开始给它们按照顺序进行编号。 这上千个文件夹,每个文件…

Django(3)-创建第一个数据模型-ORM映射

数据库配置 根目录下settings.py 。这是个包含了 Django 项目设置的 Python 模块。 通常,这个配置文件使用 SQLite 作为默认数据库。如果你不熟悉数据库,或者只是想尝试下 Django,这是最简单的选择。Python 内置 SQLite,所以你无…